# options
options(stringsAsFactors = F)
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
knitr::opts_knit$set(progress = FALSE)



Figure 3A: Covariation of protein abundance and chromatin accessibility

# The code below is not executed because the correlation matrix is very large and takes a long time to run.

# data used to calculate protein vs atac-seq correlations
if (!exists("mm10")) mm10 <- GenomeInfoDb::Seqinfo(genome = "mm10")
snames <- as.character(GenomicRanges::seqnames(mm10)) %>%
  grep("^chrUn", ., value = TRUE, invert = TRUE) %>%
  grep("_random$", ., value = TRUE, invert = TRUE) %>%
  grep("_alt$", ., value = TRUE, invert = TRUE) %>%
  grep("_fix$", ., value = TRUE, invert = TRUE) %>%
  as_tibble() %>%
  filter(!value %in% c("chrX", "chrY", "chrM")) %$% value
autosomes <- mm10[snames]
chrom_lens_Mb <- GenomeInfoDb::seqlengths(mm10)[snames] / 1e6
chrom_lens_Mb_offset <- cumsum(chrom_lens_Mb) - chrom_lens_Mb

binwidth <- 0.5e6
bins <- GenomicRanges::tileGenome(autosomes, tilewidth=binwidth, cut.last.tile.in.chrom=TRUE)
# Some bins (e.g. at end of chroms) are very small
# Merge together any bins that are less than half binwidth with the nearest full-size bin
small_bin_idx <- which(GenomicRanges::width(bins) < binwidth/2)
small_bins <- bins[small_bin_idx]
prev_bins <- bins[small_bin_idx - 1]
#assertthat::assert_that(assertthat::are_equal(GenomicRanges::start(small_bins), GenomicRanges::end(prev_bins)+1))
ii <- setdiff(1:length(bins), c(small_bin_idx, small_bin_idx - 1))
untouched <- bins[ii]
merged <- GenomicRanges::punion(small_bins, prev_bins)
final_bins <- c(untouched, merged) %>% sort()

atac_obj <- tibble(id = rownames(counts.norm2)) %>%
  separate(id,
    into = c("chrom", "start", "end"),
    convert = TRUE, remove = FALSE
  ) %>%
  mutate(chrom = substring(chrom, 5)) %>%
  filter(chrom != "Y", chrom != "X", chrom != "MT") %>%
  mutate(chrom = paste0("chr", chrom)) %>%
  mutate(midpoint = (start + end) / 2) %>%
  mutate(start = midpoint, end = midpoint) %>%
  GenomicRanges::GRanges(seqinfo = mm10) %>%
  sort()
# will be assigning each ATAC peak to one genomic bin based on midpoint
# Find the bin that each ATAC peak falls into
peak_bins <- GenomicRanges::findOverlaps(atac_obj, final_bins)
# assertthat::assert_that(assertthat::are_equal(IRanges::from(peak_bins), 1:length(peak_bins))) # one bin for each peak


prot_dat <- all.prots %>%
   mutate(chrom = gene_chr) %>%
    select(chrom, gene_start, gene_end, protein_id) %>%
    mutate(midpoint=(gene_start+gene_end)/2) %>% 
    mutate(start=midpoint, end=midpoint) %>%
    filter(chrom != "Y", chrom != "X", chrom !="MT") %>% 
    mutate(chrom=paste0("chr", chrom)) 
prot_obj <- prot_dat %>%
  GenomicRanges::GRanges(seqinfo=mm10) %>% sort()

# Find the bin that each ATAC peak falls into
prot_bins <- GenomicRanges::findOverlaps(prot_obj, final_bins)
# assertthat::assert_that(assertthat::are_equal(IRanges::from(prot_bins), 1:length(prot_bins)))

# Modify expr.both and atac.both to include only autosomes
exprmat <- expr.esc_prot[threeway.shared.samples$sampleid, prot_obj$protein_id]
atacmat <- t(counts.norm2[atac_obj$id, threeway.shared.samples$ATAC])
rownames(atacmat) <- threeway.shared.samples$sampleid

n_eqtl <- length(prot_obj)
n_bins <- length(final_bins)
cors <- cor(exprmat, atacmat, use="pairwise.complete.obs") 
cor.prot <- cors # save to variable before getting the abs value for later.
cors <- cors %>% abs()
x <- apply(cors, 1, function(vals)
    tapply(vals, INDEX=IRanges::to(peak_bins), FUN=max, na.rm=T))
rownames(x) <- paste0("ATAC_bin", rownames(x))

#low_genes <- apply(x, 2, function(vals) sum(vals > 0.2))
#low_peaks <- apply(x, 1, function(vals) sum(vals > 0.2))
xy <- apply(x, 1, function(vals)
  tapply(vals, INDEX=IRanges::to(prot_bins), FUN=mean))
rownames(xy) <- paste0("prot_bin", rownames(xy))
genome_bins_full <- as.data.frame(final_bins) %>% as_tibble() %>%
  dplyr::rename(bin_chrom=seqnames) %>%
  mutate(bin_midpoint=(start+end)/2) %>%
  mutate(bin_width=end-start, full_size=bin_width > binwidth/2) %>%
  mutate(n=1:n()) %>%
  filter(full_size)
genome_bins <- genome_bins_full %>% select(bin_chrom, bin_midpoint, n)
x2 <- as.data.frame(xy) %>% rownames_to_column("prot_bin") %>%
  mutate(prot_bin=substring(prot_bin, 9)) %>%
  mutate(prot_bin=as.integer(prot_bin)) %>%
  inner_join(genome_bins, by=c("prot_bin"="n")) %>%
  dplyr::rename(prot_bin_chrom=bin_chrom, prot_bin_midpoint=bin_midpoint) %>%
  gather(ATAC_bin, maxcor, starts_with("ATAC")) %>%
  as_tibble() %>% mutate_if(is.factor, as.character) %>%
  mutate(ATAC_bin=as.integer(substring(ATAC_bin, 9))) %>%
  inner_join(genome_bins, by=c("ATAC_bin"="n")) %>%
  dplyr::rename(ATAC_bin_chrom=bin_chrom, ATAC_bin_midpoint=bin_midpoint)

toplot <- select(x2, prot_bin, ATAC_bin, maxcor, prot_bin_chrom ) %>%
  dplyr::rename(xpos=ATAC_bin, ypos=prot_bin) 
toplot2 <- arrange(toplot, maxcor) %>%
  mutate(size_scaled = scales::rescale(maxcor) + 0.1) %>%
  mutate(cor_trimmed = ifelse(maxcor > 0.7, 0.7, maxcor)) %>%
  mutate(alpha_scaled = scales::rescale(cor_trimmed) + 0.1)
g5.prot <- ggplot(toplot2, aes(xpos, ypos)) +
  geom_point(aes(color=cor_trimmed, size=size_scaled, alpha=alpha_scaled)) +
  scale_color_distiller(palette="RdYlBu") +
  scale_size_continuous(range=c(0.1, 3), guide="none") +
  scale_alpha_continuous(range=c(.1, 1), guide="none") +
  theme_classic() +
  theme(axis.ticks=element_blank(), 
        axis.text=element_blank(), 
        axis.line = element_blank(),
        axis.title.x = element_text(size = 32),
        axis.title.y = element_text(size = 32),
        legend.text = element_text(angle=0, hjust =0.1, size = 30),
        legend.title = element_text(angle=0, hjust =0, vjust = 0, size = 28)) +
  xlab("Position of ATAC peak") +
  ylab("Position of protein coding gene") +
  coord_cartesian(xlim=c(1, n_bins), ylim=c(1, n_bins)) +
  guides(color=guide_colorbar(title="Correlation\n", barwidth=2.5,
    barheight=10, bin=100))
ggsave(g5.prot, file = here("figures/mean_sharedProt_maxATAC_05Mb_scaled.png"),width=20, height=12)


# get the max corr protein for each ATACseq peak
(cor.prot)%>%
  as_tibble(rownames = "protein_id") %>%
  pivot_longer(starts_with("peak"), names_to = "peak_id",values_to="corr") %>%
  group_by(peak_id) %>% 
  slice_max( abs(corr), n = 5) -> max_cor_atac_prot 

t(cor.prot)%>%
  as_tibble(rownames = "peak_id") %>% 
  pivot_longer(starts_with("ENS"), names_to = "protein_id",values_to="corr") %>%
  filter( abs(corr) > 0.5)  %>%
  count(protein_id) %>%
  left_join(all.prots) -> prot.cor.genes

t(cor.prot)%>%
  as_tibble(rownames = "peak_id") %>% 
  pivot_longer(starts_with("ENS"), names_to = "protein_id",values_to="corr") %>%
  filter( abs(corr) > 0.5)  %>%
  group_by(protein_id) %>%
  mutate(n = n()) %>%
  filter(n > 100) %>%
  ungroup() %>%
  left_join(., select(all.prots, "protein_id","cor_gene"="mgi_symbol")) %>%
  left_join(atac.peak.annots) -> prot.cor.atacpeaks

save( prot.cor.genes,prot.cor.atacpeaks,max_cor_atac_prot, file = here( "_data/ATAC_prot_cor_data.RData"))
load(here("../pQTL_website/_data/ATAC_prot_cor_data.RData"))

prot.cor.atacpeaks %>%
  filter(n > 100) %>%
  #filter(!cor_gene %in% (filter(rna.cor.genes, n > 50))$mgi_symbol) %>%
  select(cor_gene, peak_id, corr) %>%
  filter( cor_gene == "Id1") %>%
  separate( peak_id, into = c("atac_chr","peak_start","peak_end"), remove = FALSE, sep="_") %>% 
  mutate( atac_chr = gsub("peak","chr",atac_chr),
          peak_start = as.numeric(peak_start),
          peak_end = as.numeric(peak_end),
          value = 1) %>% 
  # adding Id1 gene_start and gene_end
  left_join(., select(all.genes, mgi_symbol, gene_start,gene_end, gene_chr), 
            by =c("cor_gene"="mgi_symbol")) %>% 
  mutate( gene_chr = paste0("chr",gene_chr) ) -> id1_cor_peaks

# atacseq peaks
id1_cor_peaks %>%  
  select( chr = atac_chr, start = peak_start, end = peak_end, Correlation = corr) %>% 
  mutate( start = as.integer(start),
          end = as.integer(end)
          )-> id1_atac_peaks
#id1
id1_cor_peaks %>%  
  select( chr = gene_chr, start = gene_start, end = gene_end) %>% 
  mutate( start = as.integer(start),
          end = as.integer(end)
          )  -> id1_gene
library(circlize)

# to add chromosomes
chroms <- c(as.character(1:19), "X")
chrom_lens <- c( 195431559, 182107670, 160017104, 156496071, 151833620, 149721874, 145434693, 129399468, 124582650, 130685419, 122078650, 120120622 ,120387272, 124867725, 104015452, 98180002, 94984432, 90672596, 61417310 , 171028300)
names(chrom_lens) <- chroms
sectors <- tibble( chr = paste0("chr",chroms),
                   start = 0,
                   end = chrom_lens)

circos.par(start.degree = 90, gap.degree= 1)
circos.genomicInitialize(sectors, plotType = NULL)
circos.genomicTrack(id1_atac_peaks,
                    ylim = c(0,1),
                    stack = TRUE,
    panel.fun = function(region, value, ...) {
      i = getI(...)
      circos.genomicRect(region, value,
                           col = ifelse(value[[1]] > 0, "red", "blue") ,
                           border = ifelse(value[[1]] > 0, "red", "blue"))
}, track.height = 0.1, bg.border = NA)
circos.genomicTrack(stack = TRUE,
                    ylim = c(1,2),
                    panel.fun = function(x, y,...) {
                      i = getI(...)
                      chr = gsub("chr","",CELL_META$sector.index)
                      xlim = CELL_META$xlim
                      ylim = CELL_META$ylim
                      circos.rect(xlim[1], 0.5, xlim[2], 1.5, col = "black")
                      circos.text(mean(xlim),1, chr, cex = 1.5, col = "white",
                                  facing = "inside", niceFacing = TRUE)
}, track.height = 0.15, bg.border = NA)
circos.genomicLabels( distinct(id1_gene),
                      labels = "ID1", 
                      labels.side = "outside", 
                      padding = 0.01, 
                      connection_height = mm_h(0.1),
                      line_lwd = 0,
                      cex = 1)
circos.genomicLink(id1_gene,
                   id1_atac_peaks,
                   border = "black" )
Figure 3A: ID1 protein abundance shows high correlation to many chromatin regions across the genome. Circos plot showing ATAC-seq peaks where chromatin accessibility is positively (red) and negatively (blue) correlated with ID1 protein abundance (n = 112, abs(correlation) >0.5).

Figure 3A: ID1 protein abundance shows high correlation to many chromatin regions across the genome. Circos plot showing ATAC-seq peaks where chromatin accessibility is positively (red) and negatively (blue) correlated with ID1 protein abundance (n = 112, abs(correlation) >0.5).

circos.clear()


Data used to generate Figure 3A can be downloaded below.

list(id1_atac_peaks, id1_gene) %>% 
    downloadthis::download_this(
    output_name = "Figure3A data",
    output_extension = ".xlsx",
    button_label = "Download Figure 3A data as xlsx",
    button_type = "primary",
    has_icon = TRUE,
    icon = "fa fa-save"
  )


Figure S3A: Correlation between protein abundance and chromatin accessibility across the genome

knitr::include_graphics( here("mean_sharedProt_maxATAC_05Mb_scaled.png"))
Figure 3A: A heatmap of Pearson correlation coefficients between protein abundance and chromatin accessibility across the genome. Proteins encoded on the sex chromosomes were excluded from the analysis to limit sex effects due to X gene dosage. Correlation between all autosomal proteins and accessibility at ATAC-seq peaks were calculated. For plotting, proteins and chromatin regions are grouped in 5 Kb bins and the points are colored and sized by the maximum correlation value in each bin.

Figure 3A: A heatmap of Pearson correlation coefficients between protein abundance and chromatin accessibility across the genome. Proteins encoded on the sex chromosomes were excluded from the analysis to limit sex effects due to X gene dosage. Correlation between all autosomal proteins and accessibility at ATAC-seq peaks were calculated. For plotting, proteins and chromatin regions are grouped in 5 Kb bins and the points are colored and sized by the maximum correlation value in each bin.


List of chromatin regions showing high correlation to protein abundance across the genome

prot.cor.atacpeaks %>%
  filter(n > 100) %>%
  #filter(!cor_gene %in% (filter(rna.cor.genes, n > 50))$mgi_symbol) %>%
  select(cor_gene, peak_id, corr, annotation, mgi_symbol, gene_start, gene_end, gene_chr, n) %>%
  rename(`# of correalated ATAC-seq peaks` = n) %>%
  mutate(corr = formatC(corr, format = "g", digits = 2)) %>%
  group_by(peak_id) %>%
  mutate(n_gene = n()) %>%
  select(cor_gene, peak_id, corr, annotation, mgi_symbol, n_gene, `# of correalated ATAC-seq peaks`) %>%
  ungroup() %>%
  group_by(cor_gene) %>%
  ungroup() %>%
  distinct() %>%
  mutate( cor_gene = toupper(cor_gene)) %>% 
  select( `Protein`= (cor_gene),
          `Peak id` = peak_id,
          `Correlation` = corr,
          `Peak annotation (function)` = annotation, 
          `Peak annotation (gene)` = mgi_symbol,
          `# of correalated ATAC-seq peaks`,
          `# of correalated proteins` = n_gene
         ) %>% 
  create_dt()

Full list of chromatin regions that show high correlation ( abs(cor) >0.5) to proteins across the genome with annotations.


Over-representation of transcription binding sites in chromatin regions with high correlation to protein abundance across the genome

background_atac_peaks <-  tibble( peak_id = atac.peak.annots_full$peak_id ) %>%
  separate( peak_id, into = c("Chr", "Start","End"), remove = FALSE) %>%
  mutate( Chr = gsub("peak","chr",Chr)) %>% 
  makeGRangesFromDataFrame(.,
                               keep.extra.columns = F,
                               seqnames.field = c("Chr"),
                               start.field = "Start",
                               end.field = "End")

prot.cor.atacpeaks %>%
  filter(n > 100) %>%
  ungroup() %>%
  filter( corr > 0) %>% 
  left_join(., select(all.prots, "cor_gene_id" = "protein_id", "cor_gene" = "mgi_symbol")) %>%
  left_join(atac.peak.annots) %>%
  select(cor_gene_id, cor_gene, peak_id, corr, annotation, mgi_symbol) %>%
  mutate(corr = formatC(corr, format = "g", digits = 2)) %>%
  arrange(cor_gene) %>%
  filter(!is.na(mgi_symbol)) %>%
  as_tibble() %>%
  select(cor_gene, peak_id) %>%
  #filter(cor_gene =="Ahdc1") %>%
  separate( peak_id, into = c("Chr", "Start","End"), remove = FALSE) %>%
  mutate( Chr = gsub("peak","chr",Chr)) %>%
  group_by(cor_gene) %>%
  nest() %>%
  mutate(geneSet = map(data, function(df) {
    genes = makeGRangesFromDataFrame( data,
                               keep.extra.columns = F,
                               seqnames.field = c("Chr"),
                               start.field = "Start",
                               end.field = "End")
    return(genes)

  })) %>%
  select(-data) %>%
  ungroup() %>%
  mutate( userSet = seq(1:n()), type ="pos")-> all_prot_atac_peaks_pos

prot.cor.atacpeaks %>%
  filter(n > 100) %>%
  ungroup() %>%
  filter( corr < 0) %>% 
  #filter(!cor_gene %in% (filter(rna.cor.genes, n > 50))$mgi_symbol) %>%
  left_join(., select(all.prots, "cor_gene_id" = "protein_id", "cor_gene" = "mgi_symbol")) %>%
  left_join(atac.peak.annots) %>%
  select(cor_gene_id, cor_gene, peak_id, corr, annotation, mgi_symbol) %>%
  mutate(corr = formatC(corr, format = "g", digits = 2)) %>%
  arrange(cor_gene) %>%
  filter(!is.na(mgi_symbol)) %>%
  as_tibble() %>%
  select(cor_gene, peak_id) %>%
  #filter(cor_gene =="Ahdc1") %>%
  separate( peak_id, into = c("Chr", "Start","End"), remove = FALSE) %>%
  mutate( Chr = gsub("peak","chr",Chr)) %>%
  group_by(cor_gene) %>%
  nest() %>%
  mutate(geneSet = map(data, function(df) {
    genes = makeGRangesFromDataFrame( data,
                               keep.extra.columns = F,
                               seqnames.field = c("Chr"),
                               start.field = "Start",
                               end.field = "End")
    return(genes)

  })) %>%
  select(-data) %>%
  ungroup() %>%
  mutate( userSet = seq(1:n()), type ="neg")-> all_prot_atac_peaks_neg

genesSets_pos <- GRangesList(c(all_prot_atac_peaks_pos$geneSet)
)
genesSets_neg <- GRangesList(c(all_prot_atac_peaks_neg$geneSet)
)

ora_prot_unique_atac_peaks_pos <- runLOLA(genesSets_pos,
                                  background_atac_peaks,
                                  regionDB,
                                  cores=1)

ora_prot_unique_atac_peaks_neg <- runLOLA(genesSets_neg,
                                  background_atac_peaks,
                                  regionDB,
                                  cores=1)

ora_prot_unique_atac_peaks_pos$qValue <- (qvalue( 10^(-ora_prot_unique_atac_peaks_pos$pValueLog )))$qvalues

ora_prot_unique_atac_peaks_neg$qValue <- (qvalue( 10^(-ora_prot_unique_atac_peaks_neg$pValueLog )))$qvalues


ora_prot_unique_atac_peaks_neg %>% 
  left_join( select(all_prot_atac_peaks_neg, userSet, cor_gene) ) %>% 
  filter( qValue < 0.05) %>%
  filter( cellType %in% c("Embryonic Stem Cell", "ES-Bruce4","Embyonic stem cell","Embryonic Stem Cells", "Embryonic stem cells", "embryonic stem cells","embryonic stem cell") ) %>% 
  group_by(cor_gene ) %>% 
  mutate( Genes = paste( unique(antibody), collapse = ", "),
          n = n_distinct(antibody)) %>%
  arrange( desc(n)) %>% 
  mutate( cor_gene = toupper(cor_gene)) %>% 
  select( `Protein`= (cor_gene),
          `Overrepresented TF binding sites in negatively correlated ATAC-seq peaks` = Genes) %>%
  distinct() %>% 
  full_join(
    ora_prot_unique_atac_peaks_pos %>% 
      left_join( select(all_prot_atac_peaks_pos, userSet, cor_gene) ) %>% 
      filter( qValue < 0.05) %>%
      filter( cellType %in% c("Embryonic Stem Cell", "ES-Bruce4","Embyonic stem cell","Embryonic Stem Cells", "Embryonic stem cells", "embryonic stem cells","embryonic stem cell") ) %>% 
      group_by( cor_gene) %>% 
      mutate( Genes = paste( unique(antibody), collapse = ", "),
          n = n_distinct(antibody)) %>%
      arrange( desc(n)) %>% 
      mutate(cor_gene = toupper(cor_gene)) %>% 
      select( `Protein`= (cor_gene),
          `Overrepresented TF binding sites in positively correlated ATAC-seq peaks` = Genes) %>%
      distinct()
  ) -> all_lola_results

all_lola_results %>% 
  create_dt()

Over-represented transcription factor binding sites in chromatin regions showing high correlation to abundance of proteins seen as horizontal bands in Figure S3A.


Table S4: List of proteins with high correlation to ATAC-seq peaks genome wide.

The table includes additional annotations such as cellular location, Interpro domains, over-represented transcription factor binding sites in ATAC-seq peaks with negative and positive correlations, and relevant references highlighting roles in pluripotency regulation for each protein.

# get the list of proteins that show high correlation (abs(cor)>0.5) to at least 100 ATAC-seq peaks
all_annot_v98_wGO <- read_tsv( here("../pQTL_website/_data","ensembl_gene_annotations_v98_wGO.txt")) %>% 
rename( "ensembl_gene_id" = "Gene stable ID",
          "protein_id" = "Protein stable ID",
          "gene_start" = "Gene start (bp)",
          "gene_end" = "Gene end (bp)",
          "gene_chr" = "Chromosome/scaffold name",
          "mgi_symbol" = "MGI symbol",
          "gene_biotype" = "Gene type",
        "GO_term_name"="GO term name",
        "GO_term_def" = "GO term definition",
        "GO_domain" = "GO domain",
        "GO_ID"= "GO term accession"
        )

all_annot_w98_winterpro <- read_tsv( here("../pQTL_website/_data","ensembl_v98_interpro.txt")) %>% 
  rename( "ensembl_gene_id" = "Gene stable ID",
          "protein_id" = "Protein stable ID") %>% 
  select(protein_id, interpro_domains =`Interpro Description` ) %>% 
  distinct()
  

prot.cor.atacpeaks %>% 
  filter(n > 100) %>%
  ungroup() %>%
  mutate( cor_type = ifelse( corr > 0, "Positive", "Negative")) %>% 
  group_by( cor_gene, cor_type) %>% 
  count() %>% 
  pivot_wider( cor_gene, names_from = "cor_type", values_from = "n") %>% 
  mutate( sum = Positive + Negative) %>% 
  mutate( `Number of correlated ATAC-seq peaks (positive / negative)` = str_c(sum, " (",Positive,"/", Negative,") ")) %>% 
  select( cor_gene,`Number of correlated ATAC-seq peaks (positive / negative)`)  -> peak_nums

prot.cor.genes %>% 
  filter(n > 100) %>% 
  # add cellular location 
  left_join(   all_annot_v98_wGO %>%
               filter( GO_domain =="cellular_component") %>% 
               select( protein_id, 
                       GO_term_name
                       )
             ) %>% 
  group_by(mgi_symbol, protein_id, gene_chr, n) %>% 
  summarise(across(GO_term_name, str_c, collapse=" ; ")) -> prot_locations 
  
prot.cor.genes %>% 
  filter(n > 100) %>% 
  # add interpro domains 
  left_join( all_annot_w98_winterpro) %>% 
  group_by(mgi_symbol, protein_id, gene_chr, n) %>% 
  summarise(across(interpro_domains, str_c, collapse=" ; ")) -> prot_interpro_doms

peak_nums %>% 
  rename(mgi_symbol = cor_gene) %>% 
  left_join( prot_locations) %>% 
  left_join( prot_interpro_doms) %>% 
  mutate(mgi_symbol = toupper(mgi_symbol),
         gene_chr = as.numeric(gene_chr)) %>% 
  select(`Protein ID` = protein_id, 
         `Protein` = (mgi_symbol), 
         `Protein location (Chr)` = gene_chr, 
         `Cellular location` = GO_term_name,
         `Interpro domain` = interpro_domains,
         `Number of correlated ATAC-seq peaks (positive / negative)`
         ) %>%
  left_join(
    all_lola_results
  ) %>% 
  # Ahdc1 annotation is missing, fixing that
  mutate( `Cellular location` = ifelse( Protein =="AHDC1", "nucleus", `Cellular location`)) %>% 
  # add observed at the transcript level?
  mutate(`Observed at the transctript level?` = ifelse( 
    Protein %in% c("ARHGEF1","GJB3","NAPRT", "OOEP", "PHLDA2", "PUS7L"),
    "Yes", "No")) %>% 
  # add references
  mutate( 
    `Published role in pluripotency [ref]` = case_when(
      Protein == "AHDC1"~"Moreira S, Seo C, Gordon V, Xing S, Wu R, Polena E, et al. Endogenous BioID elucidates TCF7L1 interactome modulation upon GSK-3 inhibition in mouse ESCs. 2018 Oct p. 431023. doi:10.1101/431023",
      Protein =="ID1"~"Romero-Lanman, E.E., Pavlovic, S., Amlani, B., Chin, Y., and Benezra, R. (2012). Id1 Maintains Embryonic Stem Cell Self-Renewal by Up-Regulation of Nanog and Repression of Brachyury Expression. Stem Cells Dev. 21, 384–393.",
      Protein =="UHRF2"~"Walker E, Chang WY, Hunkapiller J, Cagney G, Garcha K, Torchia J, Krogan NJ, Reiter JF, Stanford WL. Polycomb-like 2 associates with PRC2 and regulates transcriptional networks during mouse embryonic stem cell self-renewal and differentiation. Cell Stem Cell. 2010 Feb 5;6(2):153-66. doi: 10.1016/j.stem.2009.12.014. PMID: 20144788; PMCID: PMC2849004."
    )) -> table_s4

writexl::write_xlsx( table_s4,
                    path = here("TableS4_Proteins_w_corr_toATACseq.xlsx"),
                    col_names = TRUE,
                    format_headers = TRUE
                    )



Figure 3B: Covariation of proteome and transcriptome across samples

shared.prot.names <- shared.genes %>%
  group_by(ensembl_gene_id) %>%
  mutate(new_symbol = paste0(mgi_symbol, "_", 1:n()),
         new_gene_id = paste0(ensembl_gene_id, "_", 1:n()))

shared_prot_mat <-  t(exprZ.esc_prot[shared.samples, shared.prot.names$protein_id])
colnames(shared_prot_mat) <- paste0(colnames(shared_prot_mat),"_protein")
shared_rna_mat <-  t(exprZ.esc_rna[shared.samples, shared.prot.names$ensembl_gene_id])
colnames(shared_rna_mat) <- paste0(colnames(shared_rna_mat),"_rna")

prot_rna_sample_cor <- rcorr( x = shared_prot_mat,
                         y = shared_rna_mat,
                         type = "pearson")


prot_rna_sample_cor_df <- as_tibble( prot_rna_sample_cor$r[colnames(shared_prot_mat), colnames(shared_rna_mat)],
                            rownames = "protein_sample") %>%
  pivot_longer( colnames(shared_rna_mat), names_to = "rna_sample", values_to = "r") %>%
  inner_join( (as_tibble( prot_rna_sample_cor$P[colnames(shared_prot_mat), colnames(shared_rna_mat)],
                            rownames = "protein_sample") %>%
      pivot_longer( colnames(shared_rna_mat), names_to = "rna_sample", values_to = "p_val") ) )


prot_rna_sample_cor_df %>%
  mutate( sampleid_prot = gsub("_protein","",protein_sample),
          sampleid_rna = gsub("_rna","", rna_sample)) %>%
  filter( sampleid_rna == sampleid_prot) %>% summarize( med_r = median(r)) -> median_cor_rna_prot

Figure3B_data <- prot_rna_sample_cor_df %>%
  mutate( sampleid_prot = gsub("_protein","",protein_sample),
          sampleid_rna = gsub("_rna","", rna_sample)) %>%
  filter( sampleid_rna == sampleid_prot) %>%
  rename( `Sample id` = sampleid_prot,
          `Correlation` = r)
Figure3B_data %>% 
  ggplot() +
  aes(x = Correlation) +
  geom_histogram( show.legend = F, binwidth = 0.01, alpha = 0.8) +
  geom_vline( aes(xintercept = median(Correlation,na.rm=T)), color = "black", linetype = "dashed", size = 1 )+
  geom_text( mapping= aes(
              x = median(Correlation,na.rm=T)-0.08,
              label = stringr::str_wrap(paste0("Median = ",round(median(Correlation,na.rm=T),2)),7), 
            ),
            y = 13,
            size = 6
          
  )+
  xlab("Cell line correlation") +
  ylab("Count") +
  theme_pubclean(base_size = 20)+
  xlim(0,0.6)+
  ylim(0,15)
Figure 3B: DO mESCs show a wide range of correlations between their transcriptome and proteome. Histogram of Pearson correlation coefficients between the transcriptome and proteome of DO mESC cell lines with matching genotypes (n = 174).

Figure 3B: DO mESCs show a wide range of correlations between their transcriptome and proteome. Histogram of Pearson correlation coefficients between the transcriptome and proteome of DO mESC cell lines with matching genotypes (n = 174).


Figure3B_data %>% 
  select(
       `Sample id` ,`Correlation` 
  ) %>% 
  mutate_if(is.numeric, round ,2) %>% 
  create_dt()

Correlation values used to generate Figure 3B.


Figure S3B-C: Variation in transcript and protein abundance

# get mean + %cv for protein abundance
var_prot <- expr.esc_prot %>%
  as_tibble(.) %>%
  summarise_all(list(~ var(., na.rm = T))) %>%
  pivot_longer(everything(),
                names_to = "protein_id",
                values_to ="var.prot") 

mean_prot <- expr.esc_prot %>%
  as_tibble(.) %>%
  summarise_all(list(~ mean(., na.rm = T))) %>% 
  pivot_longer( everything(),
                names_to = "protein_id",
                values_to ="mean.prot") 

var_prot %>% 
  full_join( mean_prot) %>% 
  mutate(sd.prot = sqrt(var.prot)) %>%
  mutate(cv.prot = 100 * sd.prot / (mean.prot)) -> all_var_prot

# get mean + %cv for transcript abundance
var_rna <- expr.esc_rna %>%
  as_tibble(.) %>%
  summarise_all(list(~ var(., na.rm = T))) %>%
  pivot_longer( everything(),
                names_to = "ensembl_gene_id",
                values_to ="var.rna") 

mean_rna <- expr.esc_rna %>%
  as_tibble(.) %>%
  summarise_all(list(~ mean(., na.rm = T))) %>% 
  pivot_longer( everything(),
                names_to = "ensembl_gene_id",
                values_to ="mean.rna") 

var_rna %>% 
  full_join( mean_rna) %>% 
  left_join( all.genes) %>% 
  mutate(sd.rna = sqrt(var.rna)) %>%
  mutate(cv.rna = 100 * sd.rna / (mean.rna)) -> all_var_rna

# join transcript + protein variation
all_var_rna %>% 
  left_join( shared.genes) %>% 
  inner_join(all_var_prot %>% 
               left_join(shared.genes)) -> all_var

# plotting figures S3b-c
all_var %>% 
  ggscatter(
    .,
    x = "mean.prot", y = "mean.rna", size = 3, alpha = 0.6,
  add = "reg.line", # Add regression line
  conf.int = TRUE, # Add confidence interval

  add.params = list(color = "blue", fill = "lightgray"), show.legend.text = FALSE,
  yscale = "log10"
) +
  stat_cor(method = "pearson", label.x = 10, label.y = 6.1) + # Add correlation coefficient
  # stat_cor(  aes(label = paste(..rr.label.., ..p.label.., sep = "~`,`~")),
  #            label.x = 0.65, label.y = 6) +# Add regression R2
  xlab("Mean protein abundance") +
  ylab("Mean transcript abundance") +
  theme_pubclean(base_size = 18) + rremove("legend") -> figure_s3b
figure_s3b <- ggpar(figure_s3b, xlim = c(5, 15))

all_var %>% 
  ggscatter(. ,
    x = "cv.prot", y = "cv.rna", size = 3, alpha = 0.6,
    add = "reg.line", # Add regression line
    conf.int = TRUE, # Add confidence interval
  
    add.params = list(color = "blue", fill = "lightgray"), show.legend.text = FALSE,
    yscale = "log10", 
    xscale = "log10"
  ) +
    stat_cor(method = "pearson", label.x = 0.9, label.y = 3.02) + # Add correlation coefficient
    # stat_cor(  aes(label = paste(..rr.label.., ..p.label.., sep = "~`,`~")),
    #            label.x = -0.01, label.y = 3) +# Add regression R2
    xlab("% CV protein abundance") +
    ylab("% CV transcript abundance") +
    theme_pubclean(base_size = 18) + rremove("legend") -> figure_s3c
figure_s3c <- ggpar( figure_s3c, xlim= c(1, 50), ylim = c(5, 1000))

ggarrange(figure_s3b, 
                      figure_s3c, 
                      nrow = 1,
                      labels = c("B","C"), 
                      font.label = list( size = 20)
                      )
Figure S3: (B, C) Scatterplots showing mean and coefficient of variation (% CV) for transcript and protein abundance for genes with both measurements (n = 7,241).

Figure S3: (B, C) Scatterplots showing mean and coefficient of variation (% CV) for transcript and protein abundance for genes with both measurements (n = 7,241).


Genes with difference in variation in transcript and protein abundance

# genes with high variation in protein abundance and low variation in transcript abundance
all_var %>%
  filter( !is.na(cv.rna), !is.na(cv.prot)) %>%
  filter( cv.prot > quantile(cv.prot, 0.75) & cv.rna < quantile(cv.rna, 0.25) ) %>%
  left_join(all.prots) -> rev_var_prots

# genes with high variation in transcript abundance and low variation in protein abundance
all_var %>%
  filter( !is.na(cv.rna), !is.na(cv.prot)) %>%
  filter( cv.prot < quantile(cv.prot, 0.25) & cv.rna > quantile(cv.rna, 0.75) ) %>%
  left_join(all.prots) -> rev_var_prots2


ora_rev_var_prots <- gost( query = unique(rev_var_prots$mgi_symbol),
                     organism = "mmusculus",
                     domain_scope = "custom",
                     custom_bg = shared.genes$mgi_symbol,
                     evcodes = TRUE,
  correction_method = "fdr"
                     )
ora_rev_var_prots$result <- filter( ora_rev_var_prots$result, term_size < 600) # nothing over-represented, empty! 

ora_rev_var_prots2 <- gost( query = unique(rev_var_prots2$mgi_symbol),
                     organism = "mmusculus",
                     domain_scope = "custom",
                     custom_bg = shared.genes$mgi_symbol,
                     evcodes = TRUE,
  correction_method = "fdr"
                     )
ora_rev_var_prots2$result <- filter( ora_rev_var_prots2$result, term_size < 600)


ora_rev_var_prots2$result %>%
 select(
    `Data source` = source,
    `Term ID` = term_id,
    `Term Name` = term_name, 
    `Term size` = term_size, 
    `# of intersecting proteins` = intersection_size,
     FDR = p_value
    ) %>% 
  mutate_if( is.numeric, formatC, digits =2) %>% 
  create_dt()

Genes with high variation in transcript and low variation in protein abundance are over-represented in ribosomal proteins.


Figure S3D

# The code below is used to generate the null distribution.
# It is commented out and loaded from the saved Rdata file because it takes too long to run within the script. 
# sample_cor <- c()
# for( i in 1:1000){
#   # randomizing the sample names 1000 times and getting correlations
# 
#   shared_prot_mat <-  t(exprZ.esc_prot[shared.samples, shared.prot.names$protein_id])
#   # randomize the sample names
#   colnames(shared_prot_mat) <- paste0( sample(colnames(shared_prot_mat), ncol(shared_prot_mat)),"_protein")
# 
#   shared_rna_mat <-  t(exprZ.esc_rna[shared.samples, shared.prot.names$ensembl_gene_id])
#   # randomize the sample names
#   colnames(shared_rna_mat) <- paste0( sample(colnames(shared_rna_mat), ncol(shared_rna_mat)),"_rna")
# 
#   measure.cor.df <- rcorr( x = shared_prot_mat,
#                          y = shared_rna_mat,
#                          type = "pearson")
# 
#   sample_cor[[i]] <- as_tibble( measure.cor.df$r[colnames(shared_prot_mat), colnames(shared_rna_mat)],
#                             rownames = "protein_sample") %>%
#   pivot_longer( colnames(shared_rna_mat), names_to = "rna_sample", values_to = "r") %>%
#   inner_join( (as_tibble( measure.cor.df$P[colnames(shared_prot_mat), colnames(shared_rna_mat)],
#                             rownames = "protein_sample") %>%
#       pivot_longer( colnames(shared_rna_mat), names_to = "rna_sample", values_to = "p_val") ) ) %>%
#     mutate( n = i)
# 
# }
# 
# save(sample_cor, file = here("_data","rna_prot_sample_cor_perm_pearson.RData"))


load(here("../pQTL_website/_data","rna_prot_sample_cor_perm_pearson.RData"))

sample_cor %>% 
  enframe() %>% 
  unnest(value) %>% 
  mutate( protein_sample = gsub("_protein","",protein_sample) ,
          rna_sample = gsub("_rna","",rna_sample)) %>% 
  filter( protein_sample == rna_sample) -> null_sample_cor_dist

prot_rna_sample_cor_df %>%
  mutate( sampleid_prot = gsub("_protein","",protein_sample),
          sampleid_rna = gsub("_rna","", rna_sample)) %>%
  filter( sampleid_rna == sampleid_prot) -> real_sample_cor_dist

null_sample_cor_dist %>% 
  mutate( type = "Null") %>% 
  select( type, r) %>% 
  rbind( real_sample_cor_dist %>% 
           mutate( type = "Real") %>% 
           select( type, r)) %>% 
  ggplot()+
  aes( x = type,
       y = r, 
       col = type )+
  geom_violin( show.legend = F)+
  geom_boxplot(width = 0.1, show.legend = F)+
  scale_color_manual( values = c("black","blue"))+
  theme_pubclean(base_size = 18)+
  theme(legend.position="none")+
  ylab("Correlation")+
  xlab("Distribution")+
  stat_compare_means( label.y = 0.62, label.x = 1.15)+
  ylim(-0.5,.65) -> fig_s3d
  
ggarrange(fig_s3d, 
          labels = "D",
          font.label = list( size = 20)
                      )
Figure S3D: Genetically identical cell lines show significantly higher correlation than what is expected by chance between the transcriptome and proteome. Violin plots overlaid with boxplots depicting the distribution of Pearson correlation coefficients between the transcriptome and proteome of genetically identical mESCs (blue) and the null distribution generated through 1000 permutations where the sample names are randomized (black).

Figure S3D: Genetically identical cell lines show significantly higher correlation than what is expected by chance between the transcriptome and proteome. Violin plots overlaid with boxplots depicting the distribution of Pearson correlation coefficients between the transcriptome and proteome of genetically identical mESCs (blue) and the null distribution generated through 1000 permutations where the sample names are randomized (black).



Figure 3C: Covariation of protein and transcript abundance across genes

# get gene names for all protein ids
shared.prot.names <- shared.genes %>%
  group_by(ensembl_gene_id) %>%
  mutate(new_symbol = paste0(mgi_symbol, "_", 1:n()),
         new_gene_id = paste0(ensembl_gene_id, "_", 1:n()))

# change id's into gene symbols
shared_prot_mat2 <-  (exprZ.esc_prot[shared.samples, shared.prot.names$protein_id])
shared_rna_mat2 <-  (exprZ.esc_rna[shared.samples, shared.prot.names$ensembl_gene_id])

# get gene level correlations
prot_rna_gene_cor <- rcorr( x = shared_prot_mat2,
                         y = shared_rna_mat2,
                         type = "pearson")

# convert gene level correlations to data frame 
prot_rna_gene_cor_df <- tibble( r =diag(prot_rna_gene_cor$r[colnames(shared_prot_mat2), colnames(shared_rna_mat2)]),
                       p_val = diag(prot_rna_gene_cor$P[colnames(shared_prot_mat2), colnames(shared_rna_mat2)]),
                       n = diag(prot_rna_gene_cor$n[colnames(shared_prot_mat2), colnames(shared_rna_mat2)]),
                       protein_id = colnames(shared_prot_mat2),
                       ensembl_gene_id = colnames(shared_rna_mat2)
                       ) %>%
  left_join(., shared.prot.names) %>%
  mutate(p_adj = p.adjust(p_val, method = "BH")) %>%
  mutate( cor = r) %>%
  arrange((desc(cor))) %>%
  mutate(rank = seq(1:n()))

# get significantly negatively and positively correlated genes and genes with not correlation (abs(cor) <0.05).
neg_cor <- prot_rna_gene_cor_df %>%
  filter( cor < 0, p_adj < 0.05)

pos_cor <- prot_rna_gene_cor_df %>%
  filter( cor > 0, p_adj < 0.05) %>%
  arrange( desc(cor) )

no_cor <- prot_rna_gene_cor_df %>%
  filter( abs(cor) < 0.05) 

# over-representation analysis with each category
ora_neg_cor <- gost( query = neg_cor$mgi_symbol,
                     organism = "mmusculus",
                     domain_scope = "custom",
                     custom_bg = prot_rna_gene_cor_df$mgi_symbol,
                     evcodes = TRUE,
  correction_method = "fdr"
                     )
ora_neg_cor$result <- filter( ora_neg_cor$result, term_size < 600)

ora_pos_cor <- gost( query = pos_cor$mgi_symbol,
                     organism = "mmusculus",
                     domain_scope = "custom",
                     custom_bg = prot_rna_gene_cor_df$mgi_symbol,
                     evcodes = TRUE,
  correction_method = "fdr"
                     )
ora_pos_cor$result <- filter( ora_pos_cor$result, term_size < 600)

ora_no_cor <- gost( query = no_cor$mgi_symbol,
                     organism = "mmusculus",
                     domain_scope = "custom",
                     custom_bg = prot_rna_gene_cor_df$mgi_symbol,
                     evcodes = TRUE,
  correction_method = "fdr"
                     )
ora_no_cor$result <- filter( ora_no_cor$result, term_size < 600)

# merge all ORA results into one data frame
ora_neg_cor$result %>%
  mutate( group = "Negative correlation") %>%
  rbind( mutate( ora_pos_cor$result, group = "Positive correlation")) %>%
  rbind( mutate( ora_no_cor$result , group = "No correlation")) -> ora_all_corr


Figure3C_data_part1 <- prot_rna_gene_cor_df %>% 
  mutate( 
    Group = case_when(
      (cor < 0 & p_adj < 0.05) ~ "Negative",
      (cor > 0 & p_adj < 0.05) ~ "Positive",
      ( abs(cor) < 0.05) ~ "Low"
    )
    ) %>% 
   select( 
    `Gene name` = mgi_symbol,
    `Protein ID` = protein_id,
    `Gene ID` = ensembl_gene_id, 
    `Correlation` = cor,
    Group
    )

# get these:
# negative: cellular respiration, mitochondrial ribosome
# no correlation: Ribosome, Spliceosome OR  cytoplasmic translation, mRNA splicing, via spliceosome
# positive correlation: extracellular region, lipid metabolic process
# rank here is the order above
# For adding the dots below the correlation histogram
Figure3C_data_part2 <- ora_all_corr %>%
  #filter(source %in% c("GO:BP","REAC","KEGG")) %>%
  filter(term_name %in% c("cellular respiration", "mitochondrial ribosome",
                          "cytoplasmic translation", "mRNA splicing, via spliceosome",
                          "extracellular region", "lipid metabolic process","X-linked inheritance") ) %>%
  select(term_name, intersection, p_value, group) %>%
  arrange(desc(p_value), group) %>%
  separate_rows(intersection) %>%
  left_join(., prot_rna_gene_cor_df, by = c("intersection" = "mgi_symbol")) %>% 
  mutate( group2 = case_when(   ( cor < 0 & p_adj < 0.05) ~ "negative",
                               ( cor > 0 & p_adj < 0.05) ~ "positive",
                               ( abs(cor) <= 0.05 ) ~ "low",
                               ( abs(cor) > 0.05 & p_adj >= 0.05) ~ "none"
                              )
  )
y_colors <- RColorBrewer::brewer.pal(n = 4, name = "Dark2")

# For adding the labels next to dots in matching color
Figure3C_data_part3 <- ora_all_corr %>%
  filter(term_name %in% c("cellular respiration", "mitochondrial ribosome",
                          "cytoplasmic translation", "mRNA splicing, via spliceosome",
                          "extracellular region", "lipid metabolic process","X-linked inheritance") ) %>%
  select(term_name, intersection, p_value, group) %>%
  mutate(term_name = paste(term_name, formatC(p_value, format = "e", digits = 2))) %>%
  separate_rows(intersection) %>%
  left_join(., prot_rna_gene_cor_df, by = c("intersection" = "mgi_symbol")) %>%
  group_by(term_name, group, p_value) %>%
  dplyr::summarize(med_cor = median(cor, na.rm = TRUE)) %>%
  mutate(y_col = ifelse(group == "Negative correlation", y_colors[2],y_colors[4]),
         y_col = ifelse(group == "No correlation", y_colors[3], y_col),
         y_col = ifelse(group == "Positive correlation", y_colors[1], y_col)) %>%
  arrange(group, p_value) 
# plot results
y_colors <- RColorBrewer::brewer.pal(n = 4, name = "Dark2")

Figure3C_data_part1 %>% 
  ggplot() +
  aes(x = Correlation) +
  geom_histogram(aes(fill = Group), show.legend = F, binwidth = 0.01, alpha = 0.7) +
  xlab("Gene correlation") +
  ylab("")+
  scale_fill_manual(limits = c( "Low",NA, "Negative", "Positive"), values = c(y_colors[3],"gray",y_colors[2],y_colors[1]) ) +
  theme_pubclean(base_size = 18, base_family = "Poppins")+
  geom_vline( aes(xintercept = median(Correlation)), linetype = 2, col = "black", size = 1) +
  annotate("text",
    x = median(Figure3C_data_part1$Correlation, na.rm = T) -0.25, y = 135,
    label = paste0("Median = \n", formatC(median(Figure3C_data_part1$Correlation, na.rm = T), digits = 1, format ="f")),
    size = 6,
    family = "Poppins"
  )+
  xlim(-0.5, 1)+
  ylim(0,150)-> p1


Figure3C_data_part2 %>% 
  arrange(cor) %>% 
  mutate(label2 = factor(paste(term_name, formatC(p_value, format = "e", digits = 2)),
    levels = Figure3C_data_part3$term_name
  )) %>%
  mutate(label = factor(intersection, levels = unique(intersection))) %>%
  ggplot() +
  aes(y = label2, x = cor, col = group2, group = term_name) +
  geom_point(show.legend = FALSE, shape = 15) +
  scale_color_manual(limits = c("low", "none", "negative", "positive"), values = c(y_colors[3],"gray",y_colors[2],y_colors[1]) ) +
  xlab("Gene correlation") +
  ylab("") +
  theme_pubclean(base_size = 20, base_family = "Poppins") +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    axis.text.y = element_text(size = 13, color = (Figure3C_data_part3$y_col))
  ) +
  scale_y_discrete(position = "right") +
  xlim(-0.5, 1)-> p2

top_row <- plot_grid(p1, NULL, rel_widths = c(1, 0.7))
bottom_row <- plot_grid(NULL, p2, rel_widths = c(0.07, 1))
ora_cor_plot<- plot_grid(top_row, bottom_row, nrow = 2, rel_heights = c(1, 1)) 

ora_cor_plot
Figure 3C: Genes show variable agreement between transcript and protein abundance in DO mESCs. Histogram depicting the distribution of pairwise Pearson correlation coefficients between transcript and protein abundance of genes with characteristic GO terms overrepresented in each category annotated underneath in matching colors (green: significantly positively correlated, orange: significantly negatively correlated, purple: genes with little or no correlation).

Figure 3C: Genes show variable agreement between transcript and protein abundance in DO mESCs. Histogram depicting the distribution of pairwise Pearson correlation coefficients between transcript and protein abundance of genes with characteristic GO terms overrepresented in each category annotated underneath in matching colors (green: significantly positively correlated, orange: significantly negatively correlated, purple: genes with little or no correlation).


Figure3C_data_part1 %>%
  mutate_if( is.numeric, round, 2) %>% 
  create_dt()

Correlation values used in plotting Figure 3C top panel with groups colored.


ora_all_corr %>%
 select(
   `Group`=group, 
   `Data source` = source,
    `Term ID` = term_id,
    `Term Name` = term_name, 
    `Term size` = term_size, 
    `# of intersecting proteins` = intersection_size,
     FDR = p_value
    ) %>% 
  mutate_if( is.numeric, formatC, digits =2) %>% 
  create_dt()

List of over-represented biological processes and pathways in genes with positive, negative and no correlation between transcript and protein abundance.


Figure S3E

prot_rna_gene_cor_df %>%
  mutate( type = ifelse( ensembl_gene_id %in% complex.gene.list$ensembl_gene_id,
                         TRUE,
                         FALSE)
          ) %>%
  ggplot() +
  aes(y = cor, x = type) +
  geom_boxplot( width = 0.25, aes( col = type), show.legend = F)+
  #geom_density(aes(col = type, fill = type), show.legend = T, bins = 400, alpha = 0.6) +
  ylab("Corelation") +
  scale_color_manual(values = c("gray","red")) +
  #ggtitle("Transcript vs Protein abundance for genes") +
  theme_pubclean(base_size = 18)+
  xlab("Complex forming")+
  stat_compare_means(  label.x = 1.2, label.y = 1.1)+
  ylim( -.5, 1.2) -> figure_s3e


ggarrange(figure_s3e,          
          labels = "E",
          font.label = list( size = 20)
                      )
Figure S3E: Genes that do not form complexes show significantly higher correlation between transcript and protein abundance. Boxplot comparing the pairwise Pearson correlation coefficients between transcript and protein abundance for genes that are part of protein complexes (TRUE) and that do not form complexes (FALSE).

Figure S3E: Genes that do not form complexes show significantly higher correlation between transcript and protein abundance. Boxplot comparing the pairwise Pearson correlation coefficients between transcript and protein abundance for genes that are part of protein complexes (TRUE) and that do not form complexes (FALSE).

LS0tCnRpdGxlOiAiQ28tdmFyaWF0aW9uIGluIHByb3RlaW4gYWJ1bmRhbmNlLCBjaHJvbWF0aW4gYWNjZXNzaWJpbGl0eSBhbmQgdHJhbnNjcmlwdCBhYnVuZGFuY2UiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogCiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKPHN0eWxlPgpwLmNhcHRpb24gewogIGZvbnQtc2l6ZTogMWVtOwp9Cjwvc3R5bGU+CgoKYGBge3Igc2V0dXB9CgojIG9wdGlvbnMKb3B0aW9ucyhzdHJpbmdzQXNGYWN0b3JzID0gRikKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBGQUxTRSkKCmBgYAoKPGJyPgo8YnI+CgojIyMgRmlndXJlIDNBOiBDb3ZhcmlhdGlvbiBvZiBwcm90ZWluIGFidW5kYW5jZSBhbmQgY2hyb21hdGluIGFjY2Vzc2liaWxpdHkKCgpgYGB7ciBQcm90ZWluX2F0YWNfU2VxX2NvciwgZXZhbCA9IEZBTFNFfQojIFRoZSBjb2RlIGJlbG93IGlzIG5vdCBleGVjdXRlZCBiZWNhdXNlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggaXMgdmVyeSBsYXJnZSBhbmQgdGFrZXMgYSBsb25nIHRpbWUgdG8gcnVuLgoKIyBkYXRhIHVzZWQgdG8gY2FsY3VsYXRlIHByb3RlaW4gdnMgYXRhYy1zZXEgY29ycmVsYXRpb25zCmlmICghZXhpc3RzKCJtbTEwIikpIG1tMTAgPC0gR2Vub21lSW5mb0RiOjpTZXFpbmZvKGdlbm9tZSA9ICJtbTEwIikKc25hbWVzIDwtIGFzLmNoYXJhY3RlcihHZW5vbWljUmFuZ2VzOjpzZXFuYW1lcyhtbTEwKSkgJT4lCiAgZ3JlcCgiXmNoclVuIiwgLiwgdmFsdWUgPSBUUlVFLCBpbnZlcnQgPSBUUlVFKSAlPiUKICBncmVwKCJfcmFuZG9tJCIsIC4sIHZhbHVlID0gVFJVRSwgaW52ZXJ0ID0gVFJVRSkgJT4lCiAgZ3JlcCgiX2FsdCQiLCAuLCB2YWx1ZSA9IFRSVUUsIGludmVydCA9IFRSVUUpICU+JQogIGdyZXAoIl9maXgkIiwgLiwgdmFsdWUgPSBUUlVFLCBpbnZlcnQgPSBUUlVFKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBmaWx0ZXIoIXZhbHVlICVpbiUgYygiY2hyWCIsICJjaHJZIiwgImNock0iKSkgJSQlIHZhbHVlCmF1dG9zb21lcyA8LSBtbTEwW3NuYW1lc10KY2hyb21fbGVuc19NYiA8LSBHZW5vbWVJbmZvRGI6OnNlcWxlbmd0aHMobW0xMClbc25hbWVzXSAvIDFlNgpjaHJvbV9sZW5zX01iX29mZnNldCA8LSBjdW1zdW0oY2hyb21fbGVuc19NYikgLSBjaHJvbV9sZW5zX01iCgpiaW53aWR0aCA8LSAwLjVlNgpiaW5zIDwtIEdlbm9taWNSYW5nZXM6OnRpbGVHZW5vbWUoYXV0b3NvbWVzLCB0aWxld2lkdGg9Ymlud2lkdGgsIGN1dC5sYXN0LnRpbGUuaW4uY2hyb209VFJVRSkKIyBTb21lIGJpbnMgKGUuZy4gYXQgZW5kIG9mIGNocm9tcykgYXJlIHZlcnkgc21hbGwKIyBNZXJnZSB0b2dldGhlciBhbnkgYmlucyB0aGF0IGFyZSBsZXNzIHRoYW4gaGFsZiBiaW53aWR0aCB3aXRoIHRoZSBuZWFyZXN0IGZ1bGwtc2l6ZSBiaW4Kc21hbGxfYmluX2lkeCA8LSB3aGljaChHZW5vbWljUmFuZ2VzOjp3aWR0aChiaW5zKSA8IGJpbndpZHRoLzIpCnNtYWxsX2JpbnMgPC0gYmluc1tzbWFsbF9iaW5faWR4XQpwcmV2X2JpbnMgPC0gYmluc1tzbWFsbF9iaW5faWR4IC0gMV0KI2Fzc2VydHRoYXQ6OmFzc2VydF90aGF0KGFzc2VydHRoYXQ6OmFyZV9lcXVhbChHZW5vbWljUmFuZ2VzOjpzdGFydChzbWFsbF9iaW5zKSwgR2Vub21pY1Jhbmdlczo6ZW5kKHByZXZfYmlucykrMSkpCmlpIDwtIHNldGRpZmYoMTpsZW5ndGgoYmlucyksIGMoc21hbGxfYmluX2lkeCwgc21hbGxfYmluX2lkeCAtIDEpKQp1bnRvdWNoZWQgPC0gYmluc1tpaV0KbWVyZ2VkIDwtIEdlbm9taWNSYW5nZXM6OnB1bmlvbihzbWFsbF9iaW5zLCBwcmV2X2JpbnMpCmZpbmFsX2JpbnMgPC0gYyh1bnRvdWNoZWQsIG1lcmdlZCkgJT4lIHNvcnQoKQoKYXRhY19vYmogPC0gdGliYmxlKGlkID0gcm93bmFtZXMoY291bnRzLm5vcm0yKSkgJT4lCiAgc2VwYXJhdGUoaWQsCiAgICBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiksCiAgICBjb252ZXJ0ID0gVFJVRSwgcmVtb3ZlID0gRkFMU0UKICApICU+JQogIG11dGF0ZShjaHJvbSA9IHN1YnN0cmluZyhjaHJvbSwgNSkpICU+JQogIGZpbHRlcihjaHJvbSAhPSAiWSIsIGNocm9tICE9ICJYIiwgY2hyb20gIT0gIk1UIikgJT4lCiAgbXV0YXRlKGNocm9tID0gcGFzdGUwKCJjaHIiLCBjaHJvbSkpICU+JQogIG11dGF0ZShtaWRwb2ludCA9IChzdGFydCArIGVuZCkgLyAyKSAlPiUKICBtdXRhdGUoc3RhcnQgPSBtaWRwb2ludCwgZW5kID0gbWlkcG9pbnQpICU+JQogIEdlbm9taWNSYW5nZXM6OkdSYW5nZXMoc2VxaW5mbyA9IG1tMTApICU+JQogIHNvcnQoKQojIHdpbGwgYmUgYXNzaWduaW5nIGVhY2ggQVRBQyBwZWFrIHRvIG9uZSBnZW5vbWljIGJpbiBiYXNlZCBvbiBtaWRwb2ludAojIEZpbmQgdGhlIGJpbiB0aGF0IGVhY2ggQVRBQyBwZWFrIGZhbGxzIGludG8KcGVha19iaW5zIDwtIEdlbm9taWNSYW5nZXM6OmZpbmRPdmVybGFwcyhhdGFjX29iaiwgZmluYWxfYmlucykKIyBhc3NlcnR0aGF0Ojphc3NlcnRfdGhhdChhc3NlcnR0aGF0OjphcmVfZXF1YWwoSVJhbmdlczo6ZnJvbShwZWFrX2JpbnMpLCAxOmxlbmd0aChwZWFrX2JpbnMpKSkgIyBvbmUgYmluIGZvciBlYWNoIHBlYWsKCgpwcm90X2RhdCA8LSBhbGwucHJvdHMgJT4lCiAgIG11dGF0ZShjaHJvbSA9IGdlbmVfY2hyKSAlPiUKICAgIHNlbGVjdChjaHJvbSwgZ2VuZV9zdGFydCwgZ2VuZV9lbmQsIHByb3RlaW5faWQpICU+JQogICAgbXV0YXRlKG1pZHBvaW50PShnZW5lX3N0YXJ0K2dlbmVfZW5kKS8yKSAlPiUgCiAgICBtdXRhdGUoc3RhcnQ9bWlkcG9pbnQsIGVuZD1taWRwb2ludCkgJT4lCiAgICBmaWx0ZXIoY2hyb20gIT0gIlkiLCBjaHJvbSAhPSAiWCIsIGNocm9tICE9Ik1UIikgJT4lIAogICAgbXV0YXRlKGNocm9tPXBhc3RlMCgiY2hyIiwgY2hyb20pKSAKcHJvdF9vYmogPC0gcHJvdF9kYXQgJT4lCiAgR2Vub21pY1Jhbmdlczo6R1JhbmdlcyhzZXFpbmZvPW1tMTApICU+JSBzb3J0KCkKCiMgRmluZCB0aGUgYmluIHRoYXQgZWFjaCBBVEFDIHBlYWsgZmFsbHMgaW50bwpwcm90X2JpbnMgPC0gR2Vub21pY1Jhbmdlczo6ZmluZE92ZXJsYXBzKHByb3Rfb2JqLCBmaW5hbF9iaW5zKQojIGFzc2VydHRoYXQ6OmFzc2VydF90aGF0KGFzc2VydHRoYXQ6OmFyZV9lcXVhbChJUmFuZ2VzOjpmcm9tKHByb3RfYmlucyksIDE6bGVuZ3RoKHByb3RfYmlucykpKQoKIyBNb2RpZnkgZXhwci5ib3RoIGFuZCBhdGFjLmJvdGggdG8gaW5jbHVkZSBvbmx5IGF1dG9zb21lcwpleHBybWF0IDwtIGV4cHIuZXNjX3Byb3RbdGhyZWV3YXkuc2hhcmVkLnNhbXBsZXMkc2FtcGxlaWQsIHByb3Rfb2JqJHByb3RlaW5faWRdCmF0YWNtYXQgPC0gdChjb3VudHMubm9ybTJbYXRhY19vYmokaWQsIHRocmVld2F5LnNoYXJlZC5zYW1wbGVzJEFUQUNdKQpyb3duYW1lcyhhdGFjbWF0KSA8LSB0aHJlZXdheS5zaGFyZWQuc2FtcGxlcyRzYW1wbGVpZAoKbl9lcXRsIDwtIGxlbmd0aChwcm90X29iaikKbl9iaW5zIDwtIGxlbmd0aChmaW5hbF9iaW5zKQpjb3JzIDwtIGNvcihleHBybWF0LCBhdGFjbWF0LCB1c2U9InBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpIApjb3IucHJvdCA8LSBjb3JzICMgc2F2ZSB0byB2YXJpYWJsZSBiZWZvcmUgZ2V0dGluZyB0aGUgYWJzIHZhbHVlIGZvciBsYXRlci4KY29ycyA8LSBjb3JzICU+JSBhYnMoKQp4IDwtIGFwcGx5KGNvcnMsIDEsIGZ1bmN0aW9uKHZhbHMpCiAgICB0YXBwbHkodmFscywgSU5ERVg9SVJhbmdlczo6dG8ocGVha19iaW5zKSwgRlVOPW1heCwgbmEucm09VCkpCnJvd25hbWVzKHgpIDwtIHBhc3RlMCgiQVRBQ19iaW4iLCByb3duYW1lcyh4KSkKCiNsb3dfZ2VuZXMgPC0gYXBwbHkoeCwgMiwgZnVuY3Rpb24odmFscykgc3VtKHZhbHMgPiAwLjIpKQojbG93X3BlYWtzIDwtIGFwcGx5KHgsIDEsIGZ1bmN0aW9uKHZhbHMpIHN1bSh2YWxzID4gMC4yKSkKeHkgPC0gYXBwbHkoeCwgMSwgZnVuY3Rpb24odmFscykKICB0YXBwbHkodmFscywgSU5ERVg9SVJhbmdlczo6dG8ocHJvdF9iaW5zKSwgRlVOPW1lYW4pKQpyb3duYW1lcyh4eSkgPC0gcGFzdGUwKCJwcm90X2JpbiIsIHJvd25hbWVzKHh5KSkKZ2Vub21lX2JpbnNfZnVsbCA8LSBhcy5kYXRhLmZyYW1lKGZpbmFsX2JpbnMpICU+JSBhc190aWJibGUoKSAlPiUKICBkcGx5cjo6cmVuYW1lKGJpbl9jaHJvbT1zZXFuYW1lcykgJT4lCiAgbXV0YXRlKGJpbl9taWRwb2ludD0oc3RhcnQrZW5kKS8yKSAlPiUKICBtdXRhdGUoYmluX3dpZHRoPWVuZC1zdGFydCwgZnVsbF9zaXplPWJpbl93aWR0aCA+IGJpbndpZHRoLzIpICU+JQogIG11dGF0ZShuPTE6bigpKSAlPiUKICBmaWx0ZXIoZnVsbF9zaXplKQpnZW5vbWVfYmlucyA8LSBnZW5vbWVfYmluc19mdWxsICU+JSBzZWxlY3QoYmluX2Nocm9tLCBiaW5fbWlkcG9pbnQsIG4pCngyIDwtIGFzLmRhdGEuZnJhbWUoeHkpICU+JSByb3duYW1lc190b19jb2x1bW4oInByb3RfYmluIikgJT4lCiAgbXV0YXRlKHByb3RfYmluPXN1YnN0cmluZyhwcm90X2JpbiwgOSkpICU+JQogIG11dGF0ZShwcm90X2Jpbj1hcy5pbnRlZ2VyKHByb3RfYmluKSkgJT4lCiAgaW5uZXJfam9pbihnZW5vbWVfYmlucywgYnk9YygicHJvdF9iaW4iPSJuIikpICU+JQogIGRwbHlyOjpyZW5hbWUocHJvdF9iaW5fY2hyb209YmluX2Nocm9tLCBwcm90X2Jpbl9taWRwb2ludD1iaW5fbWlkcG9pbnQpICU+JQogIGdhdGhlcihBVEFDX2JpbiwgbWF4Y29yLCBzdGFydHNfd2l0aCgiQVRBQyIpKSAlPiUKICBhc190aWJibGUoKSAlPiUgbXV0YXRlX2lmKGlzLmZhY3RvciwgYXMuY2hhcmFjdGVyKSAlPiUKICBtdXRhdGUoQVRBQ19iaW49YXMuaW50ZWdlcihzdWJzdHJpbmcoQVRBQ19iaW4sIDkpKSkgJT4lCiAgaW5uZXJfam9pbihnZW5vbWVfYmlucywgYnk9YygiQVRBQ19iaW4iPSJuIikpICU+JQogIGRwbHlyOjpyZW5hbWUoQVRBQ19iaW5fY2hyb209YmluX2Nocm9tLCBBVEFDX2Jpbl9taWRwb2ludD1iaW5fbWlkcG9pbnQpCgp0b3Bsb3QgPC0gc2VsZWN0KHgyLCBwcm90X2JpbiwgQVRBQ19iaW4sIG1heGNvciwgcHJvdF9iaW5fY2hyb20gKSAlPiUKICBkcGx5cjo6cmVuYW1lKHhwb3M9QVRBQ19iaW4sIHlwb3M9cHJvdF9iaW4pIAp0b3Bsb3QyIDwtIGFycmFuZ2UodG9wbG90LCBtYXhjb3IpICU+JQogIG11dGF0ZShzaXplX3NjYWxlZCA9IHNjYWxlczo6cmVzY2FsZShtYXhjb3IpICsgMC4xKSAlPiUKICBtdXRhdGUoY29yX3RyaW1tZWQgPSBpZmVsc2UobWF4Y29yID4gMC43LCAwLjcsIG1heGNvcikpICU+JQogIG11dGF0ZShhbHBoYV9zY2FsZWQgPSBzY2FsZXM6OnJlc2NhbGUoY29yX3RyaW1tZWQpICsgMC4xKQpnNS5wcm90IDwtIGdncGxvdCh0b3Bsb3QyLCBhZXMoeHBvcywgeXBvcykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1jb3JfdHJpbW1lZCwgc2l6ZT1zaXplX3NjYWxlZCwgYWxwaGE9YWxwaGFfc2NhbGVkKSkgKwogIHNjYWxlX2NvbG9yX2Rpc3RpbGxlcihwYWxldHRlPSJSZFlsQnUiKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlPWMoMC4xLCAzKSwgZ3VpZGU9Im5vbmUiKSArCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZT1jKC4xLCAxKSwgZ3VpZGU9Im5vbmUiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTAsIGhqdXN0ID0wLjEsIHNpemUgPSAzMCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGFuZ2xlPTAsIGhqdXN0ID0wLCB2anVzdCA9IDAsIHNpemUgPSAyOCkpICsKICB4bGFiKCJQb3NpdGlvbiBvZiBBVEFDIHBlYWsiKSArCiAgeWxhYigiUG9zaXRpb24gb2YgcHJvdGVpbiBjb2RpbmcgZ2VuZSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDEsIG5fYmlucyksIHlsaW09YygxLCBuX2JpbnMpKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlPSJDb3JyZWxhdGlvblxuIiwgYmFyd2lkdGg9Mi41LAogICAgYmFyaGVpZ2h0PTEwLCBiaW49MTAwKSkKZ2dzYXZlKGc1LnByb3QsIGZpbGUgPSBoZXJlKCJmaWd1cmVzL21lYW5fc2hhcmVkUHJvdF9tYXhBVEFDXzA1TWJfc2NhbGVkLnBuZyIpLHdpZHRoPTIwLCBoZWlnaHQ9MTIpCgoKIyBnZXQgdGhlIG1heCBjb3JyIHByb3RlaW4gZm9yIGVhY2ggQVRBQ3NlcSBwZWFrCihjb3IucHJvdCklPiUKICBhc190aWJibGUocm93bmFtZXMgPSAicHJvdGVpbl9pZCIpICU+JQogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgicGVhayIpLCBuYW1lc190byA9ICJwZWFrX2lkIix2YWx1ZXNfdG89ImNvcnIiKSAlPiUKICBncm91cF9ieShwZWFrX2lkKSAlPiUgCiAgc2xpY2VfbWF4KCBhYnMoY29yciksIG4gPSA1KSAtPiBtYXhfY29yX2F0YWNfcHJvdCAKCnQoY29yLnByb3QpJT4lCiAgYXNfdGliYmxlKHJvd25hbWVzID0gInBlYWtfaWQiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKHN0YXJ0c193aXRoKCJFTlMiKSwgbmFtZXNfdG8gPSAicHJvdGVpbl9pZCIsdmFsdWVzX3RvPSJjb3JyIikgJT4lCiAgZmlsdGVyKCBhYnMoY29ycikgPiAwLjUpICAlPiUKICBjb3VudChwcm90ZWluX2lkKSAlPiUKICBsZWZ0X2pvaW4oYWxsLnByb3RzKSAtPiBwcm90LmNvci5nZW5lcwoKdChjb3IucHJvdCklPiUKICBhc190aWJibGUocm93bmFtZXMgPSAicGVha19pZCIpICU+JSAKICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoIkVOUyIpLCBuYW1lc190byA9ICJwcm90ZWluX2lkIix2YWx1ZXNfdG89ImNvcnIiKSAlPiUKICBmaWx0ZXIoIGFicyhjb3JyKSA+IDAuNSkgICU+JQogIGdyb3VwX2J5KHByb3RlaW5faWQpICU+JQogIG11dGF0ZShuID0gbigpKSAlPiUKICBmaWx0ZXIobiA+IDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGxlZnRfam9pbiguLCBzZWxlY3QoYWxsLnByb3RzLCAicHJvdGVpbl9pZCIsImNvcl9nZW5lIj0ibWdpX3N5bWJvbCIpKSAlPiUKICBsZWZ0X2pvaW4oYXRhYy5wZWFrLmFubm90cykgLT4gcHJvdC5jb3IuYXRhY3BlYWtzCgpzYXZlKCBwcm90LmNvci5nZW5lcyxwcm90LmNvci5hdGFjcGVha3MsbWF4X2Nvcl9hdGFjX3Byb3QsIGZpbGUgPSBoZXJlKCAiX2RhdGEvQVRBQ19wcm90X2Nvcl9kYXRhLlJEYXRhIikpCgoKYGBgCgpgYGB7ciBGaWd1cmUzQV9wcmVwfQoKbG9hZChoZXJlKCIuLi9wUVRMX3dlYnNpdGUvX2RhdGEvQVRBQ19wcm90X2Nvcl9kYXRhLlJEYXRhIikpCgpwcm90LmNvci5hdGFjcGVha3MgJT4lCiAgZmlsdGVyKG4gPiAxMDApICU+JQogICNmaWx0ZXIoIWNvcl9nZW5lICVpbiUgKGZpbHRlcihybmEuY29yLmdlbmVzLCBuID4gNTApKSRtZ2lfc3ltYm9sKSAlPiUKICBzZWxlY3QoY29yX2dlbmUsIHBlYWtfaWQsIGNvcnIpICU+JQogIGZpbHRlciggY29yX2dlbmUgPT0gIklkMSIpICU+JQogIHNlcGFyYXRlKCBwZWFrX2lkLCBpbnRvID0gYygiYXRhY19jaHIiLCJwZWFrX3N0YXJ0IiwicGVha19lbmQiKSwgcmVtb3ZlID0gRkFMU0UsIHNlcD0iXyIpICU+JSAKICBtdXRhdGUoIGF0YWNfY2hyID0gZ3N1YigicGVhayIsImNociIsYXRhY19jaHIpLAogICAgICAgICAgcGVha19zdGFydCA9IGFzLm51bWVyaWMocGVha19zdGFydCksCiAgICAgICAgICBwZWFrX2VuZCA9IGFzLm51bWVyaWMocGVha19lbmQpLAogICAgICAgICAgdmFsdWUgPSAxKSAlPiUgCiAgIyBhZGRpbmcgSWQxIGdlbmVfc3RhcnQgYW5kIGdlbmVfZW5kCiAgbGVmdF9qb2luKC4sIHNlbGVjdChhbGwuZ2VuZXMsIG1naV9zeW1ib2wsIGdlbmVfc3RhcnQsZ2VuZV9lbmQsIGdlbmVfY2hyKSwgCiAgICAgICAgICAgIGJ5ID1jKCJjb3JfZ2VuZSI9Im1naV9zeW1ib2wiKSkgJT4lIAogIG11dGF0ZSggZ2VuZV9jaHIgPSBwYXN0ZTAoImNociIsZ2VuZV9jaHIpICkgLT4gaWQxX2Nvcl9wZWFrcwoKIyBhdGFjc2VxIHBlYWtzCmlkMV9jb3JfcGVha3MgJT4lICAKICBzZWxlY3QoIGNociA9IGF0YWNfY2hyLCBzdGFydCA9IHBlYWtfc3RhcnQsIGVuZCA9IHBlYWtfZW5kLCBDb3JyZWxhdGlvbiA9IGNvcnIpICU+JSAKICBtdXRhdGUoIHN0YXJ0ID0gYXMuaW50ZWdlcihzdGFydCksCiAgICAgICAgICBlbmQgPSBhcy5pbnRlZ2VyKGVuZCkKICAgICAgICAgICktPiBpZDFfYXRhY19wZWFrcwojaWQxCmlkMV9jb3JfcGVha3MgJT4lICAKICBzZWxlY3QoIGNociA9IGdlbmVfY2hyLCBzdGFydCA9IGdlbmVfc3RhcnQsIGVuZCA9IGdlbmVfZW5kKSAlPiUgCiAgbXV0YXRlKCBzdGFydCA9IGFzLmludGVnZXIoc3RhcnQpLAogICAgICAgICAgZW5kID0gYXMuaW50ZWdlcihlbmQpCiAgICAgICAgICApICAtPiBpZDFfZ2VuZQoKYGBgCgoKYGBge3IgRmlndXJlM0FfcGxvdCwgZmlnLmNhcD0iRmlndXJlIDNBOiBJRDEgcHJvdGVpbiBhYnVuZGFuY2Ugc2hvd3MgaGlnaCBjb3JyZWxhdGlvbiB0byBtYW55IGNocm9tYXRpbiByZWdpb25zIGFjcm9zcyB0aGUgZ2Vub21lLiBDaXJjb3MgcGxvdCBzaG93aW5nIEFUQUMtc2VxIHBlYWtzIHdoZXJlIGNocm9tYXRpbiBhY2Nlc3NpYmlsaXR5IGlzIHBvc2l0aXZlbHkgKHJlZCkgYW5kIG5lZ2F0aXZlbHkgKGJsdWUpIGNvcnJlbGF0ZWQgd2l0aCBJRDEgcHJvdGVpbiBhYnVuZGFuY2UgKG4gPSAxMTIsIGFicyhjb3JyZWxhdGlvbikgPjAuNSkuIiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Nn0KCmxpYnJhcnkoY2lyY2xpemUpCgojIHRvIGFkZCBjaHJvbW9zb21lcwpjaHJvbXMgPC0gYyhhcy5jaGFyYWN0ZXIoMToxOSksICJYIikKY2hyb21fbGVucyA8LSBjKCAxOTU0MzE1NTksIDE4MjEwNzY3MCwgMTYwMDE3MTA0LCAxNTY0OTYwNzEsIDE1MTgzMzYyMCwgMTQ5NzIxODc0LCAxNDU0MzQ2OTMsIDEyOTM5OTQ2OCwgMTI0NTgyNjUwLCAxMzA2ODU0MTksIDEyMjA3ODY1MCwgMTIwMTIwNjIyICwxMjAzODcyNzIsIDEyNDg2NzcyNSwgMTA0MDE1NDUyLCA5ODE4MDAwMiwgOTQ5ODQ0MzIsIDkwNjcyNTk2LCA2MTQxNzMxMCAsIDE3MTAyODMwMCkKbmFtZXMoY2hyb21fbGVucykgPC0gY2hyb21zCnNlY3RvcnMgPC0gdGliYmxlKCBjaHIgPSBwYXN0ZTAoImNociIsY2hyb21zKSwKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMCwKICAgICAgICAgICAgICAgICAgIGVuZCA9IGNocm9tX2xlbnMpCgpjaXJjb3MucGFyKHN0YXJ0LmRlZ3JlZSA9IDkwLCBnYXAuZGVncmVlPSAxKQpjaXJjb3MuZ2Vub21pY0luaXRpYWxpemUoc2VjdG9ycywgcGxvdFR5cGUgPSBOVUxMKQpjaXJjb3MuZ2Vub21pY1RyYWNrKGlkMV9hdGFjX3BlYWtzLAogICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsMSksCiAgICAgICAgICAgICAgICAgICAgc3RhY2sgPSBUUlVFLAogICAgcGFuZWwuZnVuID0gZnVuY3Rpb24ocmVnaW9uLCB2YWx1ZSwgLi4uKSB7CiAgICAgIGkgPSBnZXRJKC4uLikKICAgICAgY2lyY29zLmdlbm9taWNSZWN0KHJlZ2lvbiwgdmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGlmZWxzZSh2YWx1ZVtbMV1dID4gMCwgInJlZCIsICJibHVlIikgLAogICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXIgPSBpZmVsc2UodmFsdWVbWzFdXSA+IDAsICJyZWQiLCAiYmx1ZSIpKQp9LCB0cmFjay5oZWlnaHQgPSAwLjEsIGJnLmJvcmRlciA9IE5BKQpjaXJjb3MuZ2Vub21pY1RyYWNrKHN0YWNrID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICB5bGltID0gYygxLDIpLAogICAgICAgICAgICAgICAgICAgIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHgsIHksLi4uKSB7CiAgICAgICAgICAgICAgICAgICAgICBpID0gZ2V0SSguLi4pCiAgICAgICAgICAgICAgICAgICAgICBjaHIgPSBnc3ViKCJjaHIiLCIiLENFTExfTUVUQSRzZWN0b3IuaW5kZXgpCiAgICAgICAgICAgICAgICAgICAgICB4bGltID0gQ0VMTF9NRVRBJHhsaW0KICAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBDRUxMX01FVEEkeWxpbQogICAgICAgICAgICAgICAgICAgICAgY2lyY29zLnJlY3QoeGxpbVsxXSwgMC41LCB4bGltWzJdLCAxLjUsIGNvbCA9ICJibGFjayIpCiAgICAgICAgICAgICAgICAgICAgICBjaXJjb3MudGV4dChtZWFuKHhsaW0pLDEsIGNociwgY2V4ID0gMS41LCBjb2wgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjaW5nID0gImluc2lkZSIsIG5pY2VGYWNpbmcgPSBUUlVFKQp9LCB0cmFjay5oZWlnaHQgPSAwLjE1LCBiZy5ib3JkZXIgPSBOQSkKY2lyY29zLmdlbm9taWNMYWJlbHMoIGRpc3RpbmN0KGlkMV9nZW5lKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9ICJJRDEiLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscy5zaWRlID0gIm91dHNpZGUiLCAKICAgICAgICAgICAgICAgICAgICAgIHBhZGRpbmcgPSAwLjAxLCAKICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25faGVpZ2h0ID0gbW1faCgwLjEpLAogICAgICAgICAgICAgICAgICAgICAgbGluZV9sd2QgPSAwLAogICAgICAgICAgICAgICAgICAgICAgY2V4ID0gMSkKY2lyY29zLmdlbm9taWNMaW5rKGlkMV9nZW5lLAogICAgICAgICAgICAgICAgICAgaWQxX2F0YWNfcGVha3MsCiAgICAgICAgICAgICAgICAgICBib3JkZXIgPSAiYmxhY2siICkKY2lyY29zLmNsZWFyKCkKCmBgYAoKPGJyPgoKRGF0YSB1c2VkIHRvIGdlbmVyYXRlIEZpZ3VyZSAzQSBjYW4gYmUgZG93bmxvYWRlZCBiZWxvdy4KCmBgYHtyIEZpZ3VyZV8zQV9kYXRhLCBmaWcuY2FwID0gIkRhdGEgdXNlZCBpbiBGaWd1cmUgM0EgdG8gZ2VuZXJhdGUgdGhlIGdlbm9taWMgcmVnaW9ucyBpbiB0aGUgY2lyY29zIHBsb3QuIn0KCmxpc3QoaWQxX2F0YWNfcGVha3MsIGlkMV9nZW5lKSAlPiUgCiAgICBkb3dubG9hZHRoaXM6OmRvd25sb2FkX3RoaXMoCiAgICBvdXRwdXRfbmFtZSA9ICJGaWd1cmUzQSBkYXRhIiwKICAgIG91dHB1dF9leHRlbnNpb24gPSAiLnhsc3giLAogICAgYnV0dG9uX2xhYmVsID0gIkRvd25sb2FkIEZpZ3VyZSAzQSBkYXRhIGFzIHhsc3giLAogICAgYnV0dG9uX3R5cGUgPSAicHJpbWFyeSIsCiAgICBoYXNfaWNvbiA9IFRSVUUsCiAgICBpY29uID0gImZhIGZhLXNhdmUiCiAgKQoKYGBgCgo8YnI+CgojIyMjIEZpZ3VyZSBTM0E6IENvcnJlbGF0aW9uIGJldHdlZW4gcHJvdGVpbiBhYnVuZGFuY2UgYW5kIGNocm9tYXRpbiBhY2Nlc3NpYmlsaXR5IGFjcm9zcyB0aGUgZ2Vub21lCgpgYGB7ciBGaWd1cmVTM0EsIGZpZy5jYXA9IkZpZ3VyZSAzQTogQSBoZWF0bWFwIG9mIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGJldHdlZW4gcHJvdGVpbiBhYnVuZGFuY2UgYW5kIGNocm9tYXRpbiBhY2Nlc3NpYmlsaXR5IGFjcm9zcyB0aGUgZ2Vub21lLiBQcm90ZWlucyBlbmNvZGVkIG9uIHRoZSBzZXggY2hyb21vc29tZXMgd2VyZSBleGNsdWRlZCBmcm9tIHRoZSBhbmFseXNpcyB0byBsaW1pdCBzZXggZWZmZWN0cyBkdWUgdG8gWCBnZW5lIGRvc2FnZS4gQ29ycmVsYXRpb24gYmV0d2VlbiBhbGwgYXV0b3NvbWFsIHByb3RlaW5zIGFuZCBhY2Nlc3NpYmlsaXR5IGF0IEFUQUMtc2VxIHBlYWtzIHdlcmUgY2FsY3VsYXRlZC4gRm9yIHBsb3R0aW5nLCBwcm90ZWlucyBhbmQgY2hyb21hdGluIHJlZ2lvbnMgYXJlIGdyb3VwZWQgaW4gNSBLYiBiaW5zIGFuZCB0aGUgcG9pbnRzIGFyZSBjb2xvcmVkIGFuZCBzaXplZCBieSB0aGUgbWF4aW11bSBjb3JyZWxhdGlvbiB2YWx1ZSBpbiBlYWNoIGJpbi4ifQoKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIGhlcmUoIm1lYW5fc2hhcmVkUHJvdF9tYXhBVEFDXzA1TWJfc2NhbGVkLnBuZyIpKQoKYGBgCgo8YnI+CgojIyMjIExpc3Qgb2YgY2hyb21hdGluIHJlZ2lvbnMgc2hvd2luZyBoaWdoIGNvcnJlbGF0aW9uIHRvIHByb3RlaW4gYWJ1bmRhbmNlIGFjcm9zcyB0aGUgZ2Vub21lCgpgYGB7ciwgZmlnLmNhcD0iRnVsbCBsaXN0IG9mIGNocm9tYXRpbiByZWdpb25zIHRoYXQgc2hvdyBoaWdoIGNvcnJlbGF0aW9uICggYWJzKGNvcikgPjAuNSkgdG8gcHJvdGVpbnMgYWNyb3NzIHRoZSBnZW5vbWUgd2l0aCBhbm5vdGF0aW9ucy4ifQoKcHJvdC5jb3IuYXRhY3BlYWtzICU+JQogIGZpbHRlcihuID4gMTAwKSAlPiUKICAjZmlsdGVyKCFjb3JfZ2VuZSAlaW4lIChmaWx0ZXIocm5hLmNvci5nZW5lcywgbiA+IDUwKSkkbWdpX3N5bWJvbCkgJT4lCiAgc2VsZWN0KGNvcl9nZW5lLCBwZWFrX2lkLCBjb3JyLCBhbm5vdGF0aW9uLCBtZ2lfc3ltYm9sLCBnZW5lX3N0YXJ0LCBnZW5lX2VuZCwgZ2VuZV9jaHIsIG4pICU+JQogIHJlbmFtZShgIyBvZiBjb3JyZWFsYXRlZCBBVEFDLXNlcSBwZWFrc2AgPSBuKSAlPiUKICBtdXRhdGUoY29yciA9IGZvcm1hdEMoY29yciwgZm9ybWF0ID0gImciLCBkaWdpdHMgPSAyKSkgJT4lCiAgZ3JvdXBfYnkocGVha19pZCkgJT4lCiAgbXV0YXRlKG5fZ2VuZSA9IG4oKSkgJT4lCiAgc2VsZWN0KGNvcl9nZW5lLCBwZWFrX2lkLCBjb3JyLCBhbm5vdGF0aW9uLCBtZ2lfc3ltYm9sLCBuX2dlbmUsIGAjIG9mIGNvcnJlYWxhdGVkIEFUQUMtc2VxIHBlYWtzYCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KGNvcl9nZW5lKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZGlzdGluY3QoKSAlPiUKICBtdXRhdGUoIGNvcl9nZW5lID0gdG91cHBlcihjb3JfZ2VuZSkpICU+JSAKICBzZWxlY3QoIGBQcm90ZWluYD0gKGNvcl9nZW5lKSwKICAgICAgICAgIGBQZWFrIGlkYCA9IHBlYWtfaWQsCiAgICAgICAgICBgQ29ycmVsYXRpb25gID0gY29yciwKICAgICAgICAgIGBQZWFrIGFubm90YXRpb24gKGZ1bmN0aW9uKWAgPSBhbm5vdGF0aW9uLCAKICAgICAgICAgIGBQZWFrIGFubm90YXRpb24gKGdlbmUpYCA9IG1naV9zeW1ib2wsCiAgICAgICAgICBgIyBvZiBjb3JyZWFsYXRlZCBBVEFDLXNlcSBwZWFrc2AsCiAgICAgICAgICBgIyBvZiBjb3JyZWFsYXRlZCBwcm90ZWluc2AgPSBuX2dlbmUKICAgICAgICAgKSAlPiUgCiAgY3JlYXRlX2R0KCkKCgpgYGAKCjxicj4KCiMjIyMgT3Zlci1yZXByZXNlbnRhdGlvbiBvZiB0cmFuc2NyaXB0aW9uIGJpbmRpbmcgc2l0ZXMgaW4gY2hyb21hdGluIHJlZ2lvbnMgd2l0aCBoaWdoIGNvcnJlbGF0aW9uIHRvIHByb3RlaW4gYWJ1bmRhbmNlIGFjcm9zcyB0aGUgZ2Vub21lCgpgYGB7ciBPUkFfQVRBQ19zZXFfcGVha3MsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5jYXA9Ik92ZXItcmVwcmVzZW50ZWQgdHJhbnNjcmlwdGlvbiBmYWN0b3IgYmluZGluZyBzaXRlcyBpbiBjaHJvbWF0aW4gcmVnaW9ucyBzaG93aW5nIGhpZ2ggY29ycmVsYXRpb24gdG8gYWJ1bmRhbmNlIG9mIHByb3RlaW5zIHNlZW4gYXMgaG9yaXpvbnRhbCBiYW5kcyBpbiBGaWd1cmUgUzNBLiJ9CgpiYWNrZ3JvdW5kX2F0YWNfcGVha3MgPC0gIHRpYmJsZSggcGVha19pZCA9IGF0YWMucGVhay5hbm5vdHNfZnVsbCRwZWFrX2lkICkgJT4lCiAgc2VwYXJhdGUoIHBlYWtfaWQsIGludG8gPSBjKCJDaHIiLCAiU3RhcnQiLCJFbmQiKSwgcmVtb3ZlID0gRkFMU0UpICU+JQogIG11dGF0ZSggQ2hyID0gZ3N1YigicGVhayIsImNociIsQ2hyKSkgJT4lIAogIG1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZSguLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcC5leHRyYS5jb2x1bW5zID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gYygiQ2hyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydC5maWVsZCA9ICJTdGFydCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQuZmllbGQgPSAiRW5kIikKCnByb3QuY29yLmF0YWNwZWFrcyAlPiUKICBmaWx0ZXIobiA+IDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlciggY29yciA+IDApICU+JSAKICBsZWZ0X2pvaW4oLiwgc2VsZWN0KGFsbC5wcm90cywgImNvcl9nZW5lX2lkIiA9ICJwcm90ZWluX2lkIiwgImNvcl9nZW5lIiA9ICJtZ2lfc3ltYm9sIikpICU+JQogIGxlZnRfam9pbihhdGFjLnBlYWsuYW5ub3RzKSAlPiUKICBzZWxlY3QoY29yX2dlbmVfaWQsIGNvcl9nZW5lLCBwZWFrX2lkLCBjb3JyLCBhbm5vdGF0aW9uLCBtZ2lfc3ltYm9sKSAlPiUKICBtdXRhdGUoY29yciA9IGZvcm1hdEMoY29yciwgZm9ybWF0ID0gImciLCBkaWdpdHMgPSAyKSkgJT4lCiAgYXJyYW5nZShjb3JfZ2VuZSkgJT4lCiAgZmlsdGVyKCFpcy5uYShtZ2lfc3ltYm9sKSkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgc2VsZWN0KGNvcl9nZW5lLCBwZWFrX2lkKSAlPiUKICAjZmlsdGVyKGNvcl9nZW5lID09IkFoZGMxIikgJT4lCiAgc2VwYXJhdGUoIHBlYWtfaWQsIGludG8gPSBjKCJDaHIiLCAiU3RhcnQiLCJFbmQiKSwgcmVtb3ZlID0gRkFMU0UpICU+JQogIG11dGF0ZSggQ2hyID0gZ3N1YigicGVhayIsImNociIsQ2hyKSkgJT4lCiAgZ3JvdXBfYnkoY29yX2dlbmUpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoZ2VuZVNldCA9IG1hcChkYXRhLCBmdW5jdGlvbihkZikgewogICAgZ2VuZXMgPSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoIGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwLmV4dHJhLmNvbHVtbnMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VxbmFtZXMuZmllbGQgPSBjKCJDaHIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0LmZpZWxkID0gIlN0YXJ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJFbmQiKQogICAgcmV0dXJuKGdlbmVzKQoKICB9KSkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKCB1c2VyU2V0ID0gc2VxKDE6bigpKSwgdHlwZSA9InBvcyIpLT4gYWxsX3Byb3RfYXRhY19wZWFrc19wb3MKCnByb3QuY29yLmF0YWNwZWFrcyAlPiUKICBmaWx0ZXIobiA+IDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlciggY29yciA8IDApICU+JSAKICAjZmlsdGVyKCFjb3JfZ2VuZSAlaW4lIChmaWx0ZXIocm5hLmNvci5nZW5lcywgbiA+IDUwKSkkbWdpX3N5bWJvbCkgJT4lCiAgbGVmdF9qb2luKC4sIHNlbGVjdChhbGwucHJvdHMsICJjb3JfZ2VuZV9pZCIgPSAicHJvdGVpbl9pZCIsICJjb3JfZ2VuZSIgPSAibWdpX3N5bWJvbCIpKSAlPiUKICBsZWZ0X2pvaW4oYXRhYy5wZWFrLmFubm90cykgJT4lCiAgc2VsZWN0KGNvcl9nZW5lX2lkLCBjb3JfZ2VuZSwgcGVha19pZCwgY29yciwgYW5ub3RhdGlvbiwgbWdpX3N5bWJvbCkgJT4lCiAgbXV0YXRlKGNvcnIgPSBmb3JtYXRDKGNvcnIsIGZvcm1hdCA9ICJnIiwgZGlnaXRzID0gMikpICU+JQogIGFycmFuZ2UoY29yX2dlbmUpICU+JQogIGZpbHRlcighaXMubmEobWdpX3N5bWJvbCkpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHNlbGVjdChjb3JfZ2VuZSwgcGVha19pZCkgJT4lCiAgI2ZpbHRlcihjb3JfZ2VuZSA9PSJBaGRjMSIpICU+JQogIHNlcGFyYXRlKCBwZWFrX2lkLCBpbnRvID0gYygiQ2hyIiwgIlN0YXJ0IiwiRW5kIiksIHJlbW92ZSA9IEZBTFNFKSAlPiUKICBtdXRhdGUoIENociA9IGdzdWIoInBlYWsiLCJjaHIiLENocikpICU+JQogIGdyb3VwX2J5KGNvcl9nZW5lKSAlPiUKICBuZXN0KCkgJT4lCiAgbXV0YXRlKGdlbmVTZXQgPSBtYXAoZGF0YSwgZnVuY3Rpb24oZGYpIHsKICAgIGdlbmVzID0gbWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKCBkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcC5leHRyYS5jb2x1bW5zID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gYygiQ2hyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydC5maWVsZCA9ICJTdGFydCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQuZmllbGQgPSAiRW5kIikKICAgIHJldHVybihnZW5lcykKCiAgfSkpICU+JQogIHNlbGVjdCgtZGF0YSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSggdXNlclNldCA9IHNlcSgxOm4oKSksIHR5cGUgPSJuZWciKS0+IGFsbF9wcm90X2F0YWNfcGVha3NfbmVnCgpnZW5lc1NldHNfcG9zIDwtIEdSYW5nZXNMaXN0KGMoYWxsX3Byb3RfYXRhY19wZWFrc19wb3MkZ2VuZVNldCkKKQpnZW5lc1NldHNfbmVnIDwtIEdSYW5nZXNMaXN0KGMoYWxsX3Byb3RfYXRhY19wZWFrc19uZWckZ2VuZVNldCkKKQoKb3JhX3Byb3RfdW5pcXVlX2F0YWNfcGVha3NfcG9zIDwtIHJ1bkxPTEEoZ2VuZXNTZXRzX3BvcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRfYXRhY19wZWFrcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbkRCLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXM9MSkKCm9yYV9wcm90X3VuaXF1ZV9hdGFjX3BlYWtzX25lZyA8LSBydW5MT0xBKGdlbmVzU2V0c19uZWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kX2F0YWNfcGVha3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb25EQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzPTEpCgpvcmFfcHJvdF91bmlxdWVfYXRhY19wZWFrc19wb3MkcVZhbHVlIDwtIChxdmFsdWUoIDEwXigtb3JhX3Byb3RfdW5pcXVlX2F0YWNfcGVha3NfcG9zJHBWYWx1ZUxvZyApKSkkcXZhbHVlcwoKb3JhX3Byb3RfdW5pcXVlX2F0YWNfcGVha3NfbmVnJHFWYWx1ZSA8LSAocXZhbHVlKCAxMF4oLW9yYV9wcm90X3VuaXF1ZV9hdGFjX3BlYWtzX25lZyRwVmFsdWVMb2cgKSkpJHF2YWx1ZXMKCgpvcmFfcHJvdF91bmlxdWVfYXRhY19wZWFrc19uZWcgJT4lIAogIGxlZnRfam9pbiggc2VsZWN0KGFsbF9wcm90X2F0YWNfcGVha3NfbmVnLCB1c2VyU2V0LCBjb3JfZ2VuZSkgKSAlPiUgCiAgZmlsdGVyKCBxVmFsdWUgPCAwLjA1KSAlPiUKICBmaWx0ZXIoIGNlbGxUeXBlICVpbiUgYygiRW1icnlvbmljIFN0ZW0gQ2VsbCIsICJFUy1CcnVjZTQiLCJFbWJ5b25pYyBzdGVtIGNlbGwiLCJFbWJyeW9uaWMgU3RlbSBDZWxscyIsICJFbWJyeW9uaWMgc3RlbSBjZWxscyIsICJlbWJyeW9uaWMgc3RlbSBjZWxscyIsImVtYnJ5b25pYyBzdGVtIGNlbGwiKSApICU+JSAKICBncm91cF9ieShjb3JfZ2VuZSApICU+JSAKICBtdXRhdGUoIEdlbmVzID0gcGFzdGUoIHVuaXF1ZShhbnRpYm9keSksIGNvbGxhcHNlID0gIiwgIiksCiAgICAgICAgICBuID0gbl9kaXN0aW5jdChhbnRpYm9keSkpICU+JQogIGFycmFuZ2UoIGRlc2MobikpICU+JSAKICBtdXRhdGUoIGNvcl9nZW5lID0gdG91cHBlcihjb3JfZ2VuZSkpICU+JSAKICBzZWxlY3QoIGBQcm90ZWluYD0gKGNvcl9nZW5lKSwKICAgICAgICAgIGBPdmVycmVwcmVzZW50ZWQgVEYgYmluZGluZyBzaXRlcyBpbiBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgQVRBQy1zZXEgcGVha3NgID0gR2VuZXMpICU+JQogIGRpc3RpbmN0KCkgJT4lIAogIGZ1bGxfam9pbigKICAgIG9yYV9wcm90X3VuaXF1ZV9hdGFjX3BlYWtzX3BvcyAlPiUgCiAgICAgIGxlZnRfam9pbiggc2VsZWN0KGFsbF9wcm90X2F0YWNfcGVha3NfcG9zLCB1c2VyU2V0LCBjb3JfZ2VuZSkgKSAlPiUgCiAgICAgIGZpbHRlciggcVZhbHVlIDwgMC4wNSkgJT4lCiAgICAgIGZpbHRlciggY2VsbFR5cGUgJWluJSBjKCJFbWJyeW9uaWMgU3RlbSBDZWxsIiwgIkVTLUJydWNlNCIsIkVtYnlvbmljIHN0ZW0gY2VsbCIsIkVtYnJ5b25pYyBTdGVtIENlbGxzIiwgIkVtYnJ5b25pYyBzdGVtIGNlbGxzIiwgImVtYnJ5b25pYyBzdGVtIGNlbGxzIiwiZW1icnlvbmljIHN0ZW0gY2VsbCIpICkgJT4lIAogICAgICBncm91cF9ieSggY29yX2dlbmUpICU+JSAKICAgICAgbXV0YXRlKCBHZW5lcyA9IHBhc3RlKCB1bmlxdWUoYW50aWJvZHkpLCBjb2xsYXBzZSA9ICIsICIpLAogICAgICAgICAgbiA9IG5fZGlzdGluY3QoYW50aWJvZHkpKSAlPiUKICAgICAgYXJyYW5nZSggZGVzYyhuKSkgJT4lIAogICAgICBtdXRhdGUoY29yX2dlbmUgPSB0b3VwcGVyKGNvcl9nZW5lKSkgJT4lIAogICAgICBzZWxlY3QoIGBQcm90ZWluYD0gKGNvcl9nZW5lKSwKICAgICAgICAgIGBPdmVycmVwcmVzZW50ZWQgVEYgYmluZGluZyBzaXRlcyBpbiBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgQVRBQy1zZXEgcGVha3NgID0gR2VuZXMpICU+JQogICAgICBkaXN0aW5jdCgpCiAgKSAtPiBhbGxfbG9sYV9yZXN1bHRzCgphbGxfbG9sYV9yZXN1bHRzICU+JSAKICBjcmVhdGVfZHQoKQoKYGBgCgo8YnI+CgojIyMjIFRhYmxlIFM0OiBMaXN0IG9mIHByb3RlaW5zIHdpdGggaGlnaCBjb3JyZWxhdGlvbiB0byBBVEFDLXNlcSBwZWFrcyBnZW5vbWUgd2lkZS4gCgpUaGUgdGFibGUgaW5jbHVkZXMgYWRkaXRpb25hbCBhbm5vdGF0aW9ucyBzdWNoIGFzIGNlbGx1bGFyIGxvY2F0aW9uLCBJbnRlcnBybyBkb21haW5zLCBvdmVyLXJlcHJlc2VudGVkIHRyYW5zY3JpcHRpb24gZmFjdG9yIGJpbmRpbmcgc2l0ZXMgaW4gQVRBQy1zZXEgcGVha3Mgd2l0aCBuZWdhdGl2ZSBhbmQgcG9zaXRpdmUgY29ycmVsYXRpb25zLCBhbmQgcmVsZXZhbnQgcmVmZXJlbmNlcyBoaWdobGlnaHRpbmcgcm9sZXMgaW4gcGx1cmlwb3RlbmN5IHJlZ3VsYXRpb24gZm9yIGVhY2ggcHJvdGVpbi4KCmBgYHtyIFRhYmxlUzQsIGV2YWwgPSBGQUxTRX0KCiMgZ2V0IHRoZSBsaXN0IG9mIHByb3RlaW5zIHRoYXQgc2hvdyBoaWdoIGNvcnJlbGF0aW9uIChhYnMoY29yKT4wLjUpIHRvIGF0IGxlYXN0IDEwMCBBVEFDLXNlcSBwZWFrcwphbGxfYW5ub3Rfdjk4X3dHTyA8LSByZWFkX3RzdiggaGVyZSgiLi4vcFFUTF93ZWJzaXRlL19kYXRhIiwiZW5zZW1ibF9nZW5lX2Fubm90YXRpb25zX3Y5OF93R08udHh0IikpICU+JSAKcmVuYW1lKCAiZW5zZW1ibF9nZW5lX2lkIiA9ICJHZW5lIHN0YWJsZSBJRCIsCiAgICAgICAgICAicHJvdGVpbl9pZCIgPSAiUHJvdGVpbiBzdGFibGUgSUQiLAogICAgICAgICAgImdlbmVfc3RhcnQiID0gIkdlbmUgc3RhcnQgKGJwKSIsCiAgICAgICAgICAiZ2VuZV9lbmQiID0gIkdlbmUgZW5kIChicCkiLAogICAgICAgICAgImdlbmVfY2hyIiA9ICJDaHJvbW9zb21lL3NjYWZmb2xkIG5hbWUiLAogICAgICAgICAgIm1naV9zeW1ib2wiID0gIk1HSSBzeW1ib2wiLAogICAgICAgICAgImdlbmVfYmlvdHlwZSIgPSAiR2VuZSB0eXBlIiwKICAgICAgICAiR09fdGVybV9uYW1lIj0iR08gdGVybSBuYW1lIiwKICAgICAgICAiR09fdGVybV9kZWYiID0gIkdPIHRlcm0gZGVmaW5pdGlvbiIsCiAgICAgICAgIkdPX2RvbWFpbiIgPSAiR08gZG9tYWluIiwKICAgICAgICAiR09fSUQiPSAiR08gdGVybSBhY2Nlc3Npb24iCiAgICAgICAgKQoKYWxsX2Fubm90X3c5OF93aW50ZXJwcm8gPC0gcmVhZF90c3YoIGhlcmUoIi4uL3BRVExfd2Vic2l0ZS9fZGF0YSIsImVuc2VtYmxfdjk4X2ludGVycHJvLnR4dCIpKSAlPiUgCiAgcmVuYW1lKCAiZW5zZW1ibF9nZW5lX2lkIiA9ICJHZW5lIHN0YWJsZSBJRCIsCiAgICAgICAgICAicHJvdGVpbl9pZCIgPSAiUHJvdGVpbiBzdGFibGUgSUQiKSAlPiUgCiAgc2VsZWN0KHByb3RlaW5faWQsIGludGVycHJvX2RvbWFpbnMgPWBJbnRlcnBybyBEZXNjcmlwdGlvbmAgKSAlPiUgCiAgZGlzdGluY3QoKQogIAoKcHJvdC5jb3IuYXRhY3BlYWtzICU+JSAKICBmaWx0ZXIobiA+IDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSggY29yX3R5cGUgPSBpZmVsc2UoIGNvcnIgPiAwLCAiUG9zaXRpdmUiLCAiTmVnYXRpdmUiKSkgJT4lIAogIGdyb3VwX2J5KCBjb3JfZ2VuZSwgY29yX3R5cGUpICU+JSAKICBjb3VudCgpICU+JSAKICBwaXZvdF93aWRlciggY29yX2dlbmUsIG5hbWVzX2Zyb20gPSAiY29yX3R5cGUiLCB2YWx1ZXNfZnJvbSA9ICJuIikgJT4lIAogIG11dGF0ZSggc3VtID0gUG9zaXRpdmUgKyBOZWdhdGl2ZSkgJT4lIAogIG11dGF0ZSggYE51bWJlciBvZiBjb3JyZWxhdGVkIEFUQUMtc2VxIHBlYWtzIChwb3NpdGl2ZSAvIG5lZ2F0aXZlKWAgPSBzdHJfYyhzdW0sICIgKCIsUG9zaXRpdmUsIi8iLCBOZWdhdGl2ZSwiKSAiKSkgJT4lIAogIHNlbGVjdCggY29yX2dlbmUsYE51bWJlciBvZiBjb3JyZWxhdGVkIEFUQUMtc2VxIHBlYWtzIChwb3NpdGl2ZSAvIG5lZ2F0aXZlKWApICAtPiBwZWFrX251bXMKCnByb3QuY29yLmdlbmVzICU+JSAKICBmaWx0ZXIobiA+IDEwMCkgJT4lIAogICMgYWRkIGNlbGx1bGFyIGxvY2F0aW9uIAogIGxlZnRfam9pbiggICBhbGxfYW5ub3Rfdjk4X3dHTyAlPiUKICAgICAgICAgICAgICAgZmlsdGVyKCBHT19kb21haW4gPT0iY2VsbHVsYXJfY29tcG9uZW50IikgJT4lIAogICAgICAgICAgICAgICBzZWxlY3QoIHByb3RlaW5faWQsIAogICAgICAgICAgICAgICAgICAgICAgIEdPX3Rlcm1fbmFtZQogICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICkgJT4lIAogIGdyb3VwX2J5KG1naV9zeW1ib2wsIHByb3RlaW5faWQsIGdlbmVfY2hyLCBuKSAlPiUgCiAgc3VtbWFyaXNlKGFjcm9zcyhHT190ZXJtX25hbWUsIHN0cl9jLCBjb2xsYXBzZT0iIDsgIikpIC0+IHByb3RfbG9jYXRpb25zIAogIApwcm90LmNvci5nZW5lcyAlPiUgCiAgZmlsdGVyKG4gPiAxMDApICU+JSAKICAjIGFkZCBpbnRlcnBybyBkb21haW5zIAogIGxlZnRfam9pbiggYWxsX2Fubm90X3c5OF93aW50ZXJwcm8pICU+JSAKICBncm91cF9ieShtZ2lfc3ltYm9sLCBwcm90ZWluX2lkLCBnZW5lX2NociwgbikgJT4lIAogIHN1bW1hcmlzZShhY3Jvc3MoaW50ZXJwcm9fZG9tYWlucywgc3RyX2MsIGNvbGxhcHNlPSIgOyAiKSkgLT4gcHJvdF9pbnRlcnByb19kb21zCgpwZWFrX251bXMgJT4lIAogIHJlbmFtZShtZ2lfc3ltYm9sID0gY29yX2dlbmUpICU+JSAKICBsZWZ0X2pvaW4oIHByb3RfbG9jYXRpb25zKSAlPiUgCiAgbGVmdF9qb2luKCBwcm90X2ludGVycHJvX2RvbXMpICU+JSAKICBtdXRhdGUobWdpX3N5bWJvbCA9IHRvdXBwZXIobWdpX3N5bWJvbCksCiAgICAgICAgIGdlbmVfY2hyID0gYXMubnVtZXJpYyhnZW5lX2NocikpICU+JSAKICBzZWxlY3QoYFByb3RlaW4gSURgID0gcHJvdGVpbl9pZCwgCiAgICAgICAgIGBQcm90ZWluYCA9IChtZ2lfc3ltYm9sKSwgCiAgICAgICAgIGBQcm90ZWluIGxvY2F0aW9uIChDaHIpYCA9IGdlbmVfY2hyLCAKICAgICAgICAgYENlbGx1bGFyIGxvY2F0aW9uYCA9IEdPX3Rlcm1fbmFtZSwKICAgICAgICAgYEludGVycHJvIGRvbWFpbmAgPSBpbnRlcnByb19kb21haW5zLAogICAgICAgICBgTnVtYmVyIG9mIGNvcnJlbGF0ZWQgQVRBQy1zZXEgcGVha3MgKHBvc2l0aXZlIC8gbmVnYXRpdmUpYAogICAgICAgICApICU+JQogIGxlZnRfam9pbigKICAgIGFsbF9sb2xhX3Jlc3VsdHMKICApICU+JSAKICAjIEFoZGMxIGFubm90YXRpb24gaXMgbWlzc2luZywgZml4aW5nIHRoYXQKICBtdXRhdGUoIGBDZWxsdWxhciBsb2NhdGlvbmAgPSBpZmVsc2UoIFByb3RlaW4gPT0iQUhEQzEiLCAibnVjbGV1cyIsIGBDZWxsdWxhciBsb2NhdGlvbmApKSAlPiUgCiAgIyBhZGQgb2JzZXJ2ZWQgYXQgdGhlIHRyYW5zY3JpcHQgbGV2ZWw/CiAgbXV0YXRlKGBPYnNlcnZlZCBhdCB0aGUgdHJhbnNjdHJpcHQgbGV2ZWw/YCA9IGlmZWxzZSggCiAgICBQcm90ZWluICVpbiUgYygiQVJIR0VGMSIsIkdKQjMiLCJOQVBSVCIsICJPT0VQIiwgIlBITERBMiIsICJQVVM3TCIpLAogICAgIlllcyIsICJObyIpKSAlPiUgCiAgIyBhZGQgcmVmZXJlbmNlcwogIG11dGF0ZSggCiAgICBgUHVibGlzaGVkIHJvbGUgaW4gcGx1cmlwb3RlbmN5IFtyZWZdYCA9IGNhc2Vfd2hlbigKICAgICAgUHJvdGVpbiA9PSAiQUhEQzEifiJNb3JlaXJhIFMsIFNlbyBDLCBHb3Jkb24gViwgWGluZyBTLCBXdSBSLCBQb2xlbmEgRSwgZXQgYWwuIEVuZG9nZW5vdXMgQmlvSUQgZWx1Y2lkYXRlcyBUQ0Y3TDEgaW50ZXJhY3RvbWUgbW9kdWxhdGlvbiB1cG9uIEdTSy0zIGluaGliaXRpb24gaW4gbW91c2UgRVNDcy4gMjAxOCBPY3QgcC4gNDMxMDIzLiBkb2k6MTAuMTEwMS80MzEwMjMiLAogICAgICBQcm90ZWluID09IklEMSJ+IlJvbWVyby1MYW5tYW4sIEUuRS4sIFBhdmxvdmljLCBTLiwgQW1sYW5pLCBCLiwgQ2hpbiwgWS4sIGFuZCBCZW5lenJhLCBSLiAoMjAxMikuIElkMSBNYWludGFpbnMgRW1icnlvbmljIFN0ZW0gQ2VsbCBTZWxmLVJlbmV3YWwgYnkgVXAtUmVndWxhdGlvbiBvZiBOYW5vZyBhbmQgUmVwcmVzc2lvbiBvZiBCcmFjaHl1cnkgRXhwcmVzc2lvbi4gU3RlbSBDZWxscyBEZXYuIDIxLCAzODTigJMzOTMuIiwKICAgICAgUHJvdGVpbiA9PSJVSFJGMiJ+IldhbGtlciBFLCBDaGFuZyBXWSwgSHVua2FwaWxsZXIgSiwgQ2FnbmV5IEcsIEdhcmNoYSBLLCBUb3JjaGlhIEosIEtyb2dhbiBOSiwgUmVpdGVyIEpGLCBTdGFuZm9yZCBXTC4gUG9seWNvbWItbGlrZSAyIGFzc29jaWF0ZXMgd2l0aCBQUkMyIGFuZCByZWd1bGF0ZXMgdHJhbnNjcmlwdGlvbmFsIG5ldHdvcmtzIGR1cmluZyBtb3VzZSBlbWJyeW9uaWMgc3RlbSBjZWxsIHNlbGYtcmVuZXdhbCBhbmQgZGlmZmVyZW50aWF0aW9uLiBDZWxsIFN0ZW0gQ2VsbC4gMjAxMCBGZWIgNTs2KDIpOjE1My02Ni4gZG9pOiAxMC4xMDE2L2ouc3RlbS4yMDA5LjEyLjAxNC4gUE1JRDogMjAxNDQ3ODg7IFBNQ0lEOiBQTUMyODQ5MDA0LiIKICAgICkpIC0+IHRhYmxlX3M0Cgp3cml0ZXhsOjp3cml0ZV94bHN4KCB0YWJsZV9zNCwKICAgICAgICAgICAgICAgICAgICBwYXRoID0gaGVyZSgiVGFibGVTNF9Qcm90ZWluc193X2NvcnJfdG9BVEFDc2VxLnhsc3giKSwKICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgIGZvcm1hdF9oZWFkZXJzID0gVFJVRQogICAgICAgICAgICAgICAgICAgICkKCmBgYAoKYGBge3IgVGFibGVTNF9kaXNwbGF5LCAgZWNobyA9RkFMU0V9CgojeGZ1bjo6ZW1iZWRfZmlsZShoZXJlKCJUYWJsZV9TNC54bHN4IikpCgpkb3dubG9hZF9maWxlKAogIHBhdGggPSBoZXJlKCJUYWJsZV9TNC54bHN4IiksCiAgb3V0cHV0X25hbWUgPSAiVGFibGVfUzQiLAogIGJ1dHRvbl9sYWJlbCA9ICJEb3dubG9hZCBUYWJsZV9TNC54bHN4IiwKICBidXR0b25fdHlwZSA9ICJwcmltYXJ5IiwKICBoYXNfaWNvbiA9IFRSVUUsCiAgaWNvbiA9ICJmYSBmYS1zYXZlIiwKICBzZWxmX2NvbnRhaW5lZCA9IEZBTFNFCikKCmBgYAoKPGJyPgo8YnI+CgojIyMgRmlndXJlIDNCOiBDb3ZhcmlhdGlvbiBvZiBwcm90ZW9tZSBhbmQgdHJhbnNjcmlwdG9tZSBhY3Jvc3Mgc2FtcGxlcwoKYGBge3IgRmlndXJlM0JfcHJlcH0KCnNoYXJlZC5wcm90Lm5hbWVzIDwtIHNoYXJlZC5nZW5lcyAlPiUKICBncm91cF9ieShlbnNlbWJsX2dlbmVfaWQpICU+JQogIG11dGF0ZShuZXdfc3ltYm9sID0gcGFzdGUwKG1naV9zeW1ib2wsICJfIiwgMTpuKCkpLAogICAgICAgICBuZXdfZ2VuZV9pZCA9IHBhc3RlMChlbnNlbWJsX2dlbmVfaWQsICJfIiwgMTpuKCkpKQoKc2hhcmVkX3Byb3RfbWF0IDwtICB0KGV4cHJaLmVzY19wcm90W3NoYXJlZC5zYW1wbGVzLCBzaGFyZWQucHJvdC5uYW1lcyRwcm90ZWluX2lkXSkKY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0KSA8LSBwYXN0ZTAoY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0KSwiX3Byb3RlaW4iKQpzaGFyZWRfcm5hX21hdCA8LSAgdChleHByWi5lc2Nfcm5hW3NoYXJlZC5zYW1wbGVzLCBzaGFyZWQucHJvdC5uYW1lcyRlbnNlbWJsX2dlbmVfaWRdKQpjb2xuYW1lcyhzaGFyZWRfcm5hX21hdCkgPC0gcGFzdGUwKGNvbG5hbWVzKHNoYXJlZF9ybmFfbWF0KSwiX3JuYSIpCgpwcm90X3JuYV9zYW1wbGVfY29yIDwtIHJjb3JyKCB4ID0gc2hhcmVkX3Byb3RfbWF0LAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHNoYXJlZF9ybmFfbWF0LAogICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwZWFyc29uIikKCgpwcm90X3JuYV9zYW1wbGVfY29yX2RmIDwtIGFzX3RpYmJsZSggcHJvdF9ybmFfc2FtcGxlX2NvciRyW2NvbG5hbWVzKHNoYXJlZF9wcm90X21hdCksIGNvbG5hbWVzKHNoYXJlZF9ybmFfbWF0KV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyA9ICJwcm90ZWluX3NhbXBsZSIpICU+JQogIHBpdm90X2xvbmdlciggY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpLCBuYW1lc190byA9ICJybmFfc2FtcGxlIiwgdmFsdWVzX3RvID0gInIiKSAlPiUKICBpbm5lcl9qb2luKCAoYXNfdGliYmxlKCBwcm90X3JuYV9zYW1wbGVfY29yJFBbY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0KSwgY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzID0gInByb3RlaW5fc2FtcGxlIikgJT4lCiAgICAgIHBpdm90X2xvbmdlciggY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpLCBuYW1lc190byA9ICJybmFfc2FtcGxlIiwgdmFsdWVzX3RvID0gInBfdmFsIikgKSApCgoKcHJvdF9ybmFfc2FtcGxlX2Nvcl9kZiAlPiUKICBtdXRhdGUoIHNhbXBsZWlkX3Byb3QgPSBnc3ViKCJfcHJvdGVpbiIsIiIscHJvdGVpbl9zYW1wbGUpLAogICAgICAgICAgc2FtcGxlaWRfcm5hID0gZ3N1YigiX3JuYSIsIiIsIHJuYV9zYW1wbGUpKSAlPiUKICBmaWx0ZXIoIHNhbXBsZWlkX3JuYSA9PSBzYW1wbGVpZF9wcm90KSAlPiUgc3VtbWFyaXplKCBtZWRfciA9IG1lZGlhbihyKSkgLT4gbWVkaWFuX2Nvcl9ybmFfcHJvdAoKRmlndXJlM0JfZGF0YSA8LSBwcm90X3JuYV9zYW1wbGVfY29yX2RmICU+JQogIG11dGF0ZSggc2FtcGxlaWRfcHJvdCA9IGdzdWIoIl9wcm90ZWluIiwiIixwcm90ZWluX3NhbXBsZSksCiAgICAgICAgICBzYW1wbGVpZF9ybmEgPSBnc3ViKCJfcm5hIiwiIiwgcm5hX3NhbXBsZSkpICU+JQogIGZpbHRlciggc2FtcGxlaWRfcm5hID09IHNhbXBsZWlkX3Byb3QpICU+JQogIHJlbmFtZSggYFNhbXBsZSBpZGAgPSBzYW1wbGVpZF9wcm90LAogICAgICAgICAgYENvcnJlbGF0aW9uYCA9IHIpCgoKYGBgCgoKYGBge3IgRmlndXJlM0IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUUsZmlnLmNhcCA9ICJGaWd1cmUgM0I6IERPIG1FU0NzIHNob3cgYSB3aWRlIHJhbmdlIG9mIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZWlyIHRyYW5zY3JpcHRvbWUgYW5kIHByb3Rlb21lLiBIaXN0b2dyYW0gb2YgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgYmV0d2VlbiB0aGUgdHJhbnNjcmlwdG9tZSBhbmQgcHJvdGVvbWUgb2YgRE8gbUVTQyBjZWxsIGxpbmVzIHdpdGggbWF0Y2hpbmcgZ2Vub3R5cGVzIChuID0gMTc0KS4iLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQoKCkZpZ3VyZTNCX2RhdGEgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IENvcnJlbGF0aW9uKSArCiAgZ2VvbV9oaXN0b2dyYW0oIHNob3cubGVnZW5kID0gRiwgYmlud2lkdGggPSAwLjAxLCBhbHBoYSA9IDAuOCkgKwogIGdlb21fdmxpbmUoIGFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuKENvcnJlbGF0aW9uLG5hLnJtPVQpKSwgY29sb3IgPSAiYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gMSApKwogIGdlb21fdGV4dCggbWFwcGluZz0gYWVzKAogICAgICAgICAgICAgIHggPSBtZWRpYW4oQ29ycmVsYXRpb24sbmEucm09VCktMC4wOCwKICAgICAgICAgICAgICBsYWJlbCA9IHN0cmluZ3I6OnN0cl93cmFwKHBhc3RlMCgiTWVkaWFuID0gIixyb3VuZChtZWRpYW4oQ29ycmVsYXRpb24sbmEucm09VCksMikpLDcpLCAKICAgICAgICAgICAgKSwKICAgICAgICAgICAgeSA9IDEzLAogICAgICAgICAgICBzaXplID0gNgogICAgICAgICAgCiAgKSsKICB4bGFiKCJDZWxsIGxpbmUgY29ycmVsYXRpb24iKSArCiAgeWxhYigiQ291bnQiKSArCiAgdGhlbWVfcHViY2xlYW4oYmFzZV9zaXplID0gMjApKwogIHhsaW0oMCwwLjYpKwogIHlsaW0oMCwxNSkKCmBgYAoKPGJyPgoKYGBge3IgRmlndXJlM0JfZGF0YSwgZmlnLmNhcD0iQ29ycmVsYXRpb24gdmFsdWVzIHVzZWQgdG8gZ2VuZXJhdGUgRmlndXJlIDNCLiJ9CgpGaWd1cmUzQl9kYXRhICU+JSAKICBzZWxlY3QoCiAgICAgICBgU2FtcGxlIGlkYCAsYENvcnJlbGF0aW9uYCAKICApICU+JSAKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgcm91bmQgLDIpICU+JSAKICBjcmVhdGVfZHQoKQoKYGBgCgo8YnI+CgojIyMjIEZpZ3VyZSBTM0ItQzogVmFyaWF0aW9uIGluIHRyYW5zY3JpcHQgYW5kIHByb3RlaW4gYWJ1bmRhbmNlCgpgYGB7ciBGaWd1cmVTM0JfQywgZmlnLmNhcCA9ICJGaWd1cmUgUzM6IChCLCBDKSBTY2F0dGVycGxvdHMgc2hvd2luZyBtZWFuIGFuZCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gKCUgQ1YpIGZvciB0cmFuc2NyaXB0IGFuZCBwcm90ZWluIGFidW5kYW5jZSBmb3IgZ2VuZXMgd2l0aCBib3RoIG1lYXN1cmVtZW50cyAobiA9IDcsMjQxKS4iLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCiMgZ2V0IG1lYW4gKyAlY3YgZm9yIHByb3RlaW4gYWJ1bmRhbmNlCnZhcl9wcm90IDwtIGV4cHIuZXNjX3Byb3QgJT4lCiAgYXNfdGliYmxlKC4pICU+JQogIHN1bW1hcmlzZV9hbGwobGlzdCh+IHZhciguLCBuYS5ybSA9IFQpKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwKICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInByb3RlaW5faWQiLAogICAgICAgICAgICAgICAgdmFsdWVzX3RvID0idmFyLnByb3QiKSAKCm1lYW5fcHJvdCA8LSBleHByLmVzY19wcm90ICU+JQogIGFzX3RpYmJsZSguKSAlPiUKICBzdW1tYXJpc2VfYWxsKGxpc3QofiBtZWFuKC4sIG5hLnJtID0gVCkpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKCBldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICBuYW1lc190byA9ICJwcm90ZWluX2lkIiwKICAgICAgICAgICAgICAgIHZhbHVlc190byA9Im1lYW4ucHJvdCIpIAoKdmFyX3Byb3QgJT4lIAogIGZ1bGxfam9pbiggbWVhbl9wcm90KSAlPiUgCiAgbXV0YXRlKHNkLnByb3QgPSBzcXJ0KHZhci5wcm90KSkgJT4lCiAgbXV0YXRlKGN2LnByb3QgPSAxMDAgKiBzZC5wcm90IC8gKG1lYW4ucHJvdCkpIC0+IGFsbF92YXJfcHJvdAoKIyBnZXQgbWVhbiArICVjdiBmb3IgdHJhbnNjcmlwdCBhYnVuZGFuY2UKdmFyX3JuYSA8LSBleHByLmVzY19ybmEgJT4lCiAgYXNfdGliYmxlKC4pICU+JQogIHN1bW1hcmlzZV9hbGwobGlzdCh+IHZhciguLCBuYS5ybSA9IFQpKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKCBldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICBuYW1lc190byA9ICJlbnNlbWJsX2dlbmVfaWQiLAogICAgICAgICAgICAgICAgdmFsdWVzX3RvID0idmFyLnJuYSIpIAoKbWVhbl9ybmEgPC0gZXhwci5lc2Nfcm5hICU+JQogIGFzX3RpYmJsZSguKSAlPiUKICBzdW1tYXJpc2VfYWxsKGxpc3QofiBtZWFuKC4sIG5hLnJtID0gVCkpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKCBldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICBuYW1lc190byA9ICJlbnNlbWJsX2dlbmVfaWQiLAogICAgICAgICAgICAgICAgdmFsdWVzX3RvID0ibWVhbi5ybmEiKSAKCnZhcl9ybmEgJT4lIAogIGZ1bGxfam9pbiggbWVhbl9ybmEpICU+JSAKICBsZWZ0X2pvaW4oIGFsbC5nZW5lcykgJT4lIAogIG11dGF0ZShzZC5ybmEgPSBzcXJ0KHZhci5ybmEpKSAlPiUKICBtdXRhdGUoY3Yucm5hID0gMTAwICogc2Qucm5hIC8gKG1lYW4ucm5hKSkgLT4gYWxsX3Zhcl9ybmEKCiMgam9pbiB0cmFuc2NyaXB0ICsgcHJvdGVpbiB2YXJpYXRpb24KYWxsX3Zhcl9ybmEgJT4lIAogIGxlZnRfam9pbiggc2hhcmVkLmdlbmVzKSAlPiUgCiAgaW5uZXJfam9pbihhbGxfdmFyX3Byb3QgJT4lIAogICAgICAgICAgICAgICBsZWZ0X2pvaW4oc2hhcmVkLmdlbmVzKSkgLT4gYWxsX3ZhcgoKIyBwbG90dGluZyBmaWd1cmVzIFMzYi1jCmFsbF92YXIgJT4lIAogIGdnc2NhdHRlcigKICAgIC4sCiAgICB4ID0gIm1lYW4ucHJvdCIsIHkgPSAibWVhbi5ybmEiLCBzaXplID0gMywgYWxwaGEgPSAwLjYsCiAgYWRkID0gInJlZy5saW5lIiwgIyBBZGQgcmVncmVzc2lvbiBsaW5lCiAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsCgogIGFkZC5wYXJhbXMgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBmaWxsID0gImxpZ2h0Z3JheSIpLCBzaG93LmxlZ2VuZC50ZXh0ID0gRkFMU0UsCiAgeXNjYWxlID0gImxvZzEwIgopICsKICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAxMCwgbGFiZWwueSA9IDYuMSkgKyAjIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudAogICMgc3RhdF9jb3IoICBhZXMobGFiZWwgPSBwYXN0ZSguLnJyLmxhYmVsLi4sIC4ucC5sYWJlbC4uLCBzZXAgPSAifmAsYH4iKSksCiAgIyAgICAgICAgICAgIGxhYmVsLnggPSAwLjY1LCBsYWJlbC55ID0gNikgKyMgQWRkIHJlZ3Jlc3Npb24gUjIKICB4bGFiKCJNZWFuIHByb3RlaW4gYWJ1bmRhbmNlIikgKwogIHlsYWIoIk1lYW4gdHJhbnNjcmlwdCBhYnVuZGFuY2UiKSArCiAgdGhlbWVfcHViY2xlYW4oYmFzZV9zaXplID0gMTgpICsgcnJlbW92ZSgibGVnZW5kIikgLT4gZmlndXJlX3MzYgpmaWd1cmVfczNiIDwtIGdncGFyKGZpZ3VyZV9zM2IsIHhsaW0gPSBjKDUsIDE1KSkKCmFsbF92YXIgJT4lIAogIGdnc2NhdHRlciguICwKICAgIHggPSAiY3YucHJvdCIsIHkgPSAiY3Yucm5hIiwgc2l6ZSA9IDMsIGFscGhhID0gMC42LAogICAgYWRkID0gInJlZy5saW5lIiwgIyBBZGQgcmVncmVzc2lvbiBsaW5lCiAgICBjb25mLmludCA9IFRSVUUsICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICAKICAgIGFkZC5wYXJhbXMgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBmaWxsID0gImxpZ2h0Z3JheSIpLCBzaG93LmxlZ2VuZC50ZXh0ID0gRkFMU0UsCiAgICB5c2NhbGUgPSAibG9nMTAiLCAKICAgIHhzY2FsZSA9ICJsb2cxMCIKICApICsKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDAuOSwgbGFiZWwueSA9IDMuMDIpICsgIyBBZGQgY29ycmVsYXRpb24gY29lZmZpY2llbnQKICAgICMgc3RhdF9jb3IoICBhZXMobGFiZWwgPSBwYXN0ZSguLnJyLmxhYmVsLi4sIC4ucC5sYWJlbC4uLCBzZXAgPSAifmAsYH4iKSksCiAgICAjICAgICAgICAgICAgbGFiZWwueCA9IC0wLjAxLCBsYWJlbC55ID0gMykgKyMgQWRkIHJlZ3Jlc3Npb24gUjIKICAgIHhsYWIoIiUgQ1YgcHJvdGVpbiBhYnVuZGFuY2UiKSArCiAgICB5bGFiKCIlIENWIHRyYW5zY3JpcHQgYWJ1bmRhbmNlIikgKwogICAgdGhlbWVfcHViY2xlYW4oYmFzZV9zaXplID0gMTgpICsgcnJlbW92ZSgibGVnZW5kIikgLT4gZmlndXJlX3MzYwpmaWd1cmVfczNjIDwtIGdncGFyKCBmaWd1cmVfczNjLCB4bGltPSBjKDEsIDUwKSwgeWxpbSA9IGMoNSwgMTAwMCkpCgpnZ2FycmFuZ2UoZmlndXJlX3MzYiwgCiAgICAgICAgICAgICAgICAgICAgICBmaWd1cmVfczNjLCAKICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQiIsIkMiKSwgCiAgICAgICAgICAgICAgICAgICAgICBmb250LmxhYmVsID0gbGlzdCggc2l6ZSA9IDIwKQogICAgICAgICAgICAgICAgICAgICAgKQoKCmBgYAoKPGJyPgoKIyMjIyBHZW5lcyB3aXRoIGRpZmZlcmVuY2UgaW4gdmFyaWF0aW9uIGluIHRyYW5zY3JpcHQgYW5kIHByb3RlaW4gYWJ1bmRhbmNlCgpgYGB7ciBUYWJsZV9wcm90X3JuYV92YXIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5jYXAgPSAiR2VuZXMgd2l0aCBoaWdoIHZhcmlhdGlvbiBpbiB0cmFuc2NyaXB0IGFuZCBsb3cgdmFyaWF0aW9uIGluIHByb3RlaW4gYWJ1bmRhbmNlIGFyZSBvdmVyLXJlcHJlc2VudGVkIGluIHJpYm9zb21hbCBwcm90ZWlucy4iLCBjYWNoZSA9IFRSVUV9CgojIGdlbmVzIHdpdGggaGlnaCB2YXJpYXRpb24gaW4gcHJvdGVpbiBhYnVuZGFuY2UgYW5kIGxvdyB2YXJpYXRpb24gaW4gdHJhbnNjcmlwdCBhYnVuZGFuY2UKYWxsX3ZhciAlPiUKICBmaWx0ZXIoICFpcy5uYShjdi5ybmEpLCAhaXMubmEoY3YucHJvdCkpICU+JQogIGZpbHRlciggY3YucHJvdCA+IHF1YW50aWxlKGN2LnByb3QsIDAuNzUpICYgY3Yucm5hIDwgcXVhbnRpbGUoY3Yucm5hLCAwLjI1KSApICU+JQogIGxlZnRfam9pbihhbGwucHJvdHMpIC0+IHJldl92YXJfcHJvdHMKCiMgZ2VuZXMgd2l0aCBoaWdoIHZhcmlhdGlvbiBpbiB0cmFuc2NyaXB0IGFidW5kYW5jZSBhbmQgbG93IHZhcmlhdGlvbiBpbiBwcm90ZWluIGFidW5kYW5jZQphbGxfdmFyICU+JQogIGZpbHRlciggIWlzLm5hKGN2LnJuYSksICFpcy5uYShjdi5wcm90KSkgJT4lCiAgZmlsdGVyKCBjdi5wcm90IDwgcXVhbnRpbGUoY3YucHJvdCwgMC4yNSkgJiBjdi5ybmEgPiBxdWFudGlsZShjdi5ybmEsIDAuNzUpICkgJT4lCiAgbGVmdF9qb2luKGFsbC5wcm90cykgLT4gcmV2X3Zhcl9wcm90czIKCgpvcmFfcmV2X3Zhcl9wcm90cyA8LSBnb3N0KCBxdWVyeSA9IHVuaXF1ZShyZXZfdmFyX3Byb3RzJG1naV9zeW1ib2wpLAogICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLAogICAgICAgICAgICAgICAgICAgICBkb21haW5fc2NvcGUgPSAiY3VzdG9tIiwKICAgICAgICAgICAgICAgICAgICAgY3VzdG9tX2JnID0gc2hhcmVkLmdlbmVzJG1naV9zeW1ib2wsCiAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIKICAgICAgICAgICAgICAgICAgICAgKQpvcmFfcmV2X3Zhcl9wcm90cyRyZXN1bHQgPC0gZmlsdGVyKCBvcmFfcmV2X3Zhcl9wcm90cyRyZXN1bHQsIHRlcm1fc2l6ZSA8IDYwMCkgIyBub3RoaW5nIG92ZXItcmVwcmVzZW50ZWQsIGVtcHR5ISAKCm9yYV9yZXZfdmFyX3Byb3RzMiA8LSBnb3N0KCBxdWVyeSA9IHVuaXF1ZShyZXZfdmFyX3Byb3RzMiRtZ2lfc3ltYm9sKSwKICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgZG9tYWluX3Njb3BlID0gImN1c3RvbSIsCiAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9iZyA9IHNoYXJlZC5nZW5lcyRtZ2lfc3ltYm9sLAogICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiCiAgICAgICAgICAgICAgICAgICAgICkKb3JhX3Jldl92YXJfcHJvdHMyJHJlc3VsdCA8LSBmaWx0ZXIoIG9yYV9yZXZfdmFyX3Byb3RzMiRyZXN1bHQsIHRlcm1fc2l6ZSA8IDYwMCkKCgpvcmFfcmV2X3Zhcl9wcm90czIkcmVzdWx0ICU+JQogc2VsZWN0KAogICAgYERhdGEgc291cmNlYCA9IHNvdXJjZSwKICAgIGBUZXJtIElEYCA9IHRlcm1faWQsCiAgICBgVGVybSBOYW1lYCA9IHRlcm1fbmFtZSwgCiAgICBgVGVybSBzaXplYCA9IHRlcm1fc2l6ZSwgCiAgICBgIyBvZiBpbnRlcnNlY3RpbmcgcHJvdGVpbnNgID0gaW50ZXJzZWN0aW9uX3NpemUsCiAgICAgRkRSID0gcF92YWx1ZQogICAgKSAlPiUgCiAgbXV0YXRlX2lmKCBpcy5udW1lcmljLCBmb3JtYXRDLCBkaWdpdHMgPTIpICU+JSAKICBjcmVhdGVfZHQoKQoKYGBgCgoKPGJyPgoKIyMjIyBGaWd1cmUgUzNECgpgYGB7ciBGaWd1cmVTM0QsIGZpZy5jYXA9IkZpZ3VyZSBTM0Q6IEdlbmV0aWNhbGx5IGlkZW50aWNhbCBjZWxsIGxpbmVzIHNob3cgc2lnbmlmaWNhbnRseSBoaWdoZXIgY29ycmVsYXRpb24gdGhhbiB3aGF0IGlzIGV4cGVjdGVkIGJ5IGNoYW5jZSBiZXR3ZWVuIHRoZSB0cmFuc2NyaXB0b21lIGFuZCBwcm90ZW9tZS4gVmlvbGluIHBsb3RzIG92ZXJsYWlkIHdpdGggYm94cGxvdHMgZGVwaWN0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgYmV0d2VlbiB0aGUgdHJhbnNjcmlwdG9tZSBhbmQgcHJvdGVvbWUgb2YgZ2VuZXRpY2FsbHkgaWRlbnRpY2FsIG1FU0NzIChibHVlKSBhbmQgdGhlIG51bGwgZGlzdHJpYnV0aW9uIGdlbmVyYXRlZCB0aHJvdWdoIDEwMDAgcGVybXV0YXRpb25zIHdoZXJlIHRoZSBzYW1wbGUgbmFtZXMgYXJlIHJhbmRvbWl6ZWQgKGJsYWNrKS4iLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD00fQoKCiMgVGhlIGNvZGUgYmVsb3cgaXMgdXNlZCB0byBnZW5lcmF0ZSB0aGUgbnVsbCBkaXN0cmlidXRpb24uCiMgSXQgaXMgY29tbWVudGVkIG91dCBhbmQgbG9hZGVkIGZyb20gdGhlIHNhdmVkIFJkYXRhIGZpbGUgYmVjYXVzZSBpdCB0YWtlcyB0b28gbG9uZyB0byBydW4gd2l0aGluIHRoZSBzY3JpcHQuIAojIHNhbXBsZV9jb3IgPC0gYygpCiMgZm9yKCBpIGluIDE6MTAwMCl7CiMgICAjIHJhbmRvbWl6aW5nIHRoZSBzYW1wbGUgbmFtZXMgMTAwMCB0aW1lcyBhbmQgZ2V0dGluZyBjb3JyZWxhdGlvbnMKIyAKIyAgIHNoYXJlZF9wcm90X21hdCA8LSAgdChleHByWi5lc2NfcHJvdFtzaGFyZWQuc2FtcGxlcywgc2hhcmVkLnByb3QubmFtZXMkcHJvdGVpbl9pZF0pCiMgICAjIHJhbmRvbWl6ZSB0aGUgc2FtcGxlIG5hbWVzCiMgICBjb2xuYW1lcyhzaGFyZWRfcHJvdF9tYXQpIDwtIHBhc3RlMCggc2FtcGxlKGNvbG5hbWVzKHNoYXJlZF9wcm90X21hdCksIG5jb2woc2hhcmVkX3Byb3RfbWF0KSksIl9wcm90ZWluIikKIyAKIyAgIHNoYXJlZF9ybmFfbWF0IDwtICB0KGV4cHJaLmVzY19ybmFbc2hhcmVkLnNhbXBsZXMsIHNoYXJlZC5wcm90Lm5hbWVzJGVuc2VtYmxfZ2VuZV9pZF0pCiMgICAjIHJhbmRvbWl6ZSB0aGUgc2FtcGxlIG5hbWVzCiMgICBjb2xuYW1lcyhzaGFyZWRfcm5hX21hdCkgPC0gcGFzdGUwKCBzYW1wbGUoY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpLCBuY29sKHNoYXJlZF9ybmFfbWF0KSksIl9ybmEiKQojIAojICAgbWVhc3VyZS5jb3IuZGYgPC0gcmNvcnIoIHggPSBzaGFyZWRfcHJvdF9tYXQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBzaGFyZWRfcm5hX21hdCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwZWFyc29uIikKIyAKIyAgIHNhbXBsZV9jb3JbW2ldXSA8LSBhc190aWJibGUoIG1lYXN1cmUuY29yLmRmJHJbY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0KSwgY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpXSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMgPSAicHJvdGVpbl9zYW1wbGUiKSAlPiUKIyAgIHBpdm90X2xvbmdlciggY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpLCBuYW1lc190byA9ICJybmFfc2FtcGxlIiwgdmFsdWVzX3RvID0gInIiKSAlPiUKIyAgIGlubmVyX2pvaW4oIChhc190aWJibGUoIG1lYXN1cmUuY29yLmRmJFBbY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0KSwgY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQpXSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMgPSAicHJvdGVpbl9zYW1wbGUiKSAlPiUKIyAgICAgICBwaXZvdF9sb25nZXIoIGNvbG5hbWVzKHNoYXJlZF9ybmFfbWF0KSwgbmFtZXNfdG8gPSAicm5hX3NhbXBsZSIsIHZhbHVlc190byA9ICJwX3ZhbCIpICkgKSAlPiUKIyAgICAgbXV0YXRlKCBuID0gaSkKIyAKIyB9CiMgCiMgc2F2ZShzYW1wbGVfY29yLCBmaWxlID0gaGVyZSgiX2RhdGEiLCJybmFfcHJvdF9zYW1wbGVfY29yX3Blcm1fcGVhcnNvbi5SRGF0YSIpKQoKCmxvYWQoaGVyZSgiLi4vcFFUTF93ZWJzaXRlL19kYXRhIiwicm5hX3Byb3Rfc2FtcGxlX2Nvcl9wZXJtX3BlYXJzb24uUkRhdGEiKSkKCnNhbXBsZV9jb3IgJT4lIAogIGVuZnJhbWUoKSAlPiUgCiAgdW5uZXN0KHZhbHVlKSAlPiUgCiAgbXV0YXRlKCBwcm90ZWluX3NhbXBsZSA9IGdzdWIoIl9wcm90ZWluIiwiIixwcm90ZWluX3NhbXBsZSkgLAogICAgICAgICAgcm5hX3NhbXBsZSA9IGdzdWIoIl9ybmEiLCIiLHJuYV9zYW1wbGUpKSAlPiUgCiAgZmlsdGVyKCBwcm90ZWluX3NhbXBsZSA9PSBybmFfc2FtcGxlKSAtPiBudWxsX3NhbXBsZV9jb3JfZGlzdAoKcHJvdF9ybmFfc2FtcGxlX2Nvcl9kZiAlPiUKICBtdXRhdGUoIHNhbXBsZWlkX3Byb3QgPSBnc3ViKCJfcHJvdGVpbiIsIiIscHJvdGVpbl9zYW1wbGUpLAogICAgICAgICAgc2FtcGxlaWRfcm5hID0gZ3N1YigiX3JuYSIsIiIsIHJuYV9zYW1wbGUpKSAlPiUKICBmaWx0ZXIoIHNhbXBsZWlkX3JuYSA9PSBzYW1wbGVpZF9wcm90KSAtPiByZWFsX3NhbXBsZV9jb3JfZGlzdAoKbnVsbF9zYW1wbGVfY29yX2Rpc3QgJT4lIAogIG11dGF0ZSggdHlwZSA9ICJOdWxsIikgJT4lIAogIHNlbGVjdCggdHlwZSwgcikgJT4lIAogIHJiaW5kKCByZWFsX3NhbXBsZV9jb3JfZGlzdCAlPiUgCiAgICAgICAgICAgbXV0YXRlKCB0eXBlID0gIlJlYWwiKSAlPiUgCiAgICAgICAgICAgc2VsZWN0KCB0eXBlLCByKSkgJT4lIAogIGdncGxvdCgpKwogIGFlcyggeCA9IHR5cGUsCiAgICAgICB5ID0gciwgCiAgICAgICBjb2wgPSB0eXBlICkrCiAgZ2VvbV92aW9saW4oIHNob3cubGVnZW5kID0gRikrCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBzaG93LmxlZ2VuZCA9IEYpKwogIHNjYWxlX2NvbG9yX21hbnVhbCggdmFsdWVzID0gYygiYmxhY2siLCJibHVlIikpKwogIHRoZW1lX3B1YmNsZWFuKGJhc2Vfc2l6ZSA9IDE4KSsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsKICB5bGFiKCJDb3JyZWxhdGlvbiIpKwogIHhsYWIoIkRpc3RyaWJ1dGlvbiIpKwogIHN0YXRfY29tcGFyZV9tZWFucyggbGFiZWwueSA9IDAuNjIsIGxhYmVsLnggPSAxLjE1KSsKICB5bGltKC0wLjUsLjY1KSAtPiBmaWdfczNkCiAgCmdnYXJyYW5nZShmaWdfczNkLCAKICAgICAgICAgIGxhYmVscyA9ICJEIiwKICAgICAgICAgIGZvbnQubGFiZWwgPSBsaXN0KCBzaXplID0gMjApCiAgICAgICAgICAgICAgICAgICAgICApCgpgYGAKCgo8YnI+Cjxicj4KCiMjIyBGaWd1cmUgM0M6IENvdmFyaWF0aW9uIG9mIHByb3RlaW4gYW5kIHRyYW5zY3JpcHQgYWJ1bmRhbmNlIGFjcm9zcyBnZW5lcwoKYGBge3IgRmlndXJlM0NfcHJlcCwgY2FjaGUgPSBUUlVFLCBjYWNoZS5sYXp5PUZBTFNFfQoKIyBnZXQgZ2VuZSBuYW1lcyBmb3IgYWxsIHByb3RlaW4gaWRzCnNoYXJlZC5wcm90Lm5hbWVzIDwtIHNoYXJlZC5nZW5lcyAlPiUKICBncm91cF9ieShlbnNlbWJsX2dlbmVfaWQpICU+JQogIG11dGF0ZShuZXdfc3ltYm9sID0gcGFzdGUwKG1naV9zeW1ib2wsICJfIiwgMTpuKCkpLAogICAgICAgICBuZXdfZ2VuZV9pZCA9IHBhc3RlMChlbnNlbWJsX2dlbmVfaWQsICJfIiwgMTpuKCkpKQoKIyBjaGFuZ2UgaWQncyBpbnRvIGdlbmUgc3ltYm9scwpzaGFyZWRfcHJvdF9tYXQyIDwtICAoZXhwclouZXNjX3Byb3Rbc2hhcmVkLnNhbXBsZXMsIHNoYXJlZC5wcm90Lm5hbWVzJHByb3RlaW5faWRdKQpzaGFyZWRfcm5hX21hdDIgPC0gIChleHByWi5lc2Nfcm5hW3NoYXJlZC5zYW1wbGVzLCBzaGFyZWQucHJvdC5uYW1lcyRlbnNlbWJsX2dlbmVfaWRdKQoKIyBnZXQgZ2VuZSBsZXZlbCBjb3JyZWxhdGlvbnMKcHJvdF9ybmFfZ2VuZV9jb3IgPC0gcmNvcnIoIHggPSBzaGFyZWRfcHJvdF9tYXQyLAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHNoYXJlZF9ybmFfbWF0MiwKICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicGVhcnNvbiIpCgojIGNvbnZlcnQgZ2VuZSBsZXZlbCBjb3JyZWxhdGlvbnMgdG8gZGF0YSBmcmFtZSAKcHJvdF9ybmFfZ2VuZV9jb3JfZGYgPC0gdGliYmxlKCByID1kaWFnKHByb3Rfcm5hX2dlbmVfY29yJHJbY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0MiksIGNvbG5hbWVzKHNoYXJlZF9ybmFfbWF0MildKSwKICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbCA9IGRpYWcocHJvdF9ybmFfZ2VuZV9jb3IkUFtjb2xuYW1lcyhzaGFyZWRfcHJvdF9tYXQyKSwgY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQyKV0pLAogICAgICAgICAgICAgICAgICAgICAgIG4gPSBkaWFnKHByb3Rfcm5hX2dlbmVfY29yJG5bY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0MiksIGNvbG5hbWVzKHNoYXJlZF9ybmFfbWF0MildKSwKICAgICAgICAgICAgICAgICAgICAgICBwcm90ZWluX2lkID0gY29sbmFtZXMoc2hhcmVkX3Byb3RfbWF0MiksCiAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibF9nZW5lX2lkID0gY29sbmFtZXMoc2hhcmVkX3JuYV9tYXQyKQogICAgICAgICAgICAgICAgICAgICAgICkgJT4lCiAgbGVmdF9qb2luKC4sIHNoYXJlZC5wcm90Lm5hbWVzKSAlPiUKICBtdXRhdGUocF9hZGogPSBwLmFkanVzdChwX3ZhbCwgbWV0aG9kID0gIkJIIikpICU+JQogIG11dGF0ZSggY29yID0gcikgJT4lCiAgYXJyYW5nZSgoZGVzYyhjb3IpKSkgJT4lCiAgbXV0YXRlKHJhbmsgPSBzZXEoMTpuKCkpKQoKIyBnZXQgc2lnbmlmaWNhbnRseSBuZWdhdGl2ZWx5IGFuZCBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgZ2VuZXMgYW5kIGdlbmVzIHdpdGggbm90IGNvcnJlbGF0aW9uIChhYnMoY29yKSA8MC4wNSkuCm5lZ19jb3IgPC0gcHJvdF9ybmFfZ2VuZV9jb3JfZGYgJT4lCiAgZmlsdGVyKCBjb3IgPCAwLCBwX2FkaiA8IDAuMDUpCgpwb3NfY29yIDwtIHByb3Rfcm5hX2dlbmVfY29yX2RmICU+JQogIGZpbHRlciggY29yID4gMCwgcF9hZGogPCAwLjA1KSAlPiUKICBhcnJhbmdlKCBkZXNjKGNvcikgKQoKbm9fY29yIDwtIHByb3Rfcm5hX2dlbmVfY29yX2RmICU+JQogIGZpbHRlciggYWJzKGNvcikgPCAwLjA1KSAKCiMgb3Zlci1yZXByZXNlbnRhdGlvbiBhbmFseXNpcyB3aXRoIGVhY2ggY2F0ZWdvcnkKb3JhX25lZ19jb3IgPC0gZ29zdCggcXVlcnkgPSBuZWdfY29yJG1naV9zeW1ib2wsCiAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgIGRvbWFpbl9zY29wZSA9ICJjdXN0b20iLAogICAgICAgICAgICAgICAgICAgICBjdXN0b21fYmcgPSBwcm90X3JuYV9nZW5lX2Nvcl9kZiRtZ2lfc3ltYm9sLAogICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiCiAgICAgICAgICAgICAgICAgICAgICkKb3JhX25lZ19jb3IkcmVzdWx0IDwtIGZpbHRlciggb3JhX25lZ19jb3IkcmVzdWx0LCB0ZXJtX3NpemUgPCA2MDApCgpvcmFfcG9zX2NvciA8LSBnb3N0KCBxdWVyeSA9IHBvc19jb3IkbWdpX3N5bWJvbCwKICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgZG9tYWluX3Njb3BlID0gImN1c3RvbSIsCiAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9iZyA9IHByb3Rfcm5hX2dlbmVfY29yX2RmJG1naV9zeW1ib2wsCiAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIKICAgICAgICAgICAgICAgICAgICAgKQpvcmFfcG9zX2NvciRyZXN1bHQgPC0gZmlsdGVyKCBvcmFfcG9zX2NvciRyZXN1bHQsIHRlcm1fc2l6ZSA8IDYwMCkKCm9yYV9ub19jb3IgPC0gZ29zdCggcXVlcnkgPSBub19jb3IkbWdpX3N5bWJvbCwKICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgZG9tYWluX3Njb3BlID0gImN1c3RvbSIsCiAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9iZyA9IHByb3Rfcm5hX2dlbmVfY29yX2RmJG1naV9zeW1ib2wsCiAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIKICAgICAgICAgICAgICAgICAgICAgKQpvcmFfbm9fY29yJHJlc3VsdCA8LSBmaWx0ZXIoIG9yYV9ub19jb3IkcmVzdWx0LCB0ZXJtX3NpemUgPCA2MDApCgojIG1lcmdlIGFsbCBPUkEgcmVzdWx0cyBpbnRvIG9uZSBkYXRhIGZyYW1lCm9yYV9uZWdfY29yJHJlc3VsdCAlPiUKICBtdXRhdGUoIGdyb3VwID0gIk5lZ2F0aXZlIGNvcnJlbGF0aW9uIikgJT4lCiAgcmJpbmQoIG11dGF0ZSggb3JhX3Bvc19jb3IkcmVzdWx0LCBncm91cCA9ICJQb3NpdGl2ZSBjb3JyZWxhdGlvbiIpKSAlPiUKICByYmluZCggbXV0YXRlKCBvcmFfbm9fY29yJHJlc3VsdCAsIGdyb3VwID0gIk5vIGNvcnJlbGF0aW9uIikpIC0+IG9yYV9hbGxfY29ycgoKCkZpZ3VyZTNDX2RhdGFfcGFydDEgPC0gcHJvdF9ybmFfZ2VuZV9jb3JfZGYgJT4lIAogIG11dGF0ZSggCiAgICBHcm91cCA9IGNhc2Vfd2hlbigKICAgICAgKGNvciA8IDAgJiBwX2FkaiA8IDAuMDUpIH4gIk5lZ2F0aXZlIiwKICAgICAgKGNvciA+IDAgJiBwX2FkaiA8IDAuMDUpIH4gIlBvc2l0aXZlIiwKICAgICAgKCBhYnMoY29yKSA8IDAuMDUpIH4gIkxvdyIKICAgICkKICAgICkgJT4lIAogICBzZWxlY3QoIAogICAgYEdlbmUgbmFtZWAgPSBtZ2lfc3ltYm9sLAogICAgYFByb3RlaW4gSURgID0gcHJvdGVpbl9pZCwKICAgIGBHZW5lIElEYCA9IGVuc2VtYmxfZ2VuZV9pZCwgCiAgICBgQ29ycmVsYXRpb25gID0gY29yLAogICAgR3JvdXAKICAgICkKCiMgZ2V0IHRoZXNlOgojIG5lZ2F0aXZlOiBjZWxsdWxhciByZXNwaXJhdGlvbiwgbWl0b2Nob25kcmlhbCByaWJvc29tZQojIG5vIGNvcnJlbGF0aW9uOiBSaWJvc29tZSwgU3BsaWNlb3NvbWUgT1IgIGN5dG9wbGFzbWljIHRyYW5zbGF0aW9uLCBtUk5BIHNwbGljaW5nLCB2aWEgc3BsaWNlb3NvbWUKIyBwb3NpdGl2ZSBjb3JyZWxhdGlvbjogZXh0cmFjZWxsdWxhciByZWdpb24sIGxpcGlkIG1ldGFib2xpYyBwcm9jZXNzCiMgcmFuayBoZXJlIGlzIHRoZSBvcmRlciBhYm92ZQojIEZvciBhZGRpbmcgdGhlIGRvdHMgYmVsb3cgdGhlIGNvcnJlbGF0aW9uIGhpc3RvZ3JhbQpGaWd1cmUzQ19kYXRhX3BhcnQyIDwtIG9yYV9hbGxfY29yciAlPiUKICAjZmlsdGVyKHNvdXJjZSAlaW4lIGMoIkdPOkJQIiwiUkVBQyIsIktFR0ciKSkgJT4lCiAgZmlsdGVyKHRlcm1fbmFtZSAlaW4lIGMoImNlbGx1bGFyIHJlc3BpcmF0aW9uIiwgIm1pdG9jaG9uZHJpYWwgcmlib3NvbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJjeXRvcGxhc21pYyB0cmFuc2xhdGlvbiIsICJtUk5BIHNwbGljaW5nLCB2aWEgc3BsaWNlb3NvbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJleHRyYWNlbGx1bGFyIHJlZ2lvbiIsICJsaXBpZCBtZXRhYm9saWMgcHJvY2VzcyIsIlgtbGlua2VkIGluaGVyaXRhbmNlIikgKSAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBpbnRlcnNlY3Rpb24sIHBfdmFsdWUsIGdyb3VwKSAlPiUKICBhcnJhbmdlKGRlc2MocF92YWx1ZSksIGdyb3VwKSAlPiUKICBzZXBhcmF0ZV9yb3dzKGludGVyc2VjdGlvbikgJT4lCiAgbGVmdF9qb2luKC4sIHByb3Rfcm5hX2dlbmVfY29yX2RmLCBieSA9IGMoImludGVyc2VjdGlvbiIgPSAibWdpX3N5bWJvbCIpKSAlPiUgCiAgbXV0YXRlKCBncm91cDIgPSBjYXNlX3doZW4oICAgKCBjb3IgPCAwICYgcF9hZGogPCAwLjA1KSB+ICJuZWdhdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoIGNvciA+IDAgJiBwX2FkaiA8IDAuMDUpIH4gInBvc2l0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICggYWJzKGNvcikgPD0gMC4wNSApIH4gImxvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoIGFicyhjb3IpID4gMC4wNSAmIHBfYWRqID49IDAuMDUpIH4gIm5vbmUiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICApCnlfY29sb3JzIDwtIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChuID0gNCwgbmFtZSA9ICJEYXJrMiIpCgojIEZvciBhZGRpbmcgdGhlIGxhYmVscyBuZXh0IHRvIGRvdHMgaW4gbWF0Y2hpbmcgY29sb3IKRmlndXJlM0NfZGF0YV9wYXJ0MyA8LSBvcmFfYWxsX2NvcnIgJT4lCiAgZmlsdGVyKHRlcm1fbmFtZSAlaW4lIGMoImNlbGx1bGFyIHJlc3BpcmF0aW9uIiwgIm1pdG9jaG9uZHJpYWwgcmlib3NvbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJjeXRvcGxhc21pYyB0cmFuc2xhdGlvbiIsICJtUk5BIHNwbGljaW5nLCB2aWEgc3BsaWNlb3NvbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJleHRyYWNlbGx1bGFyIHJlZ2lvbiIsICJsaXBpZCBtZXRhYm9saWMgcHJvY2VzcyIsIlgtbGlua2VkIGluaGVyaXRhbmNlIikgKSAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBpbnRlcnNlY3Rpb24sIHBfdmFsdWUsIGdyb3VwKSAlPiUKICBtdXRhdGUodGVybV9uYW1lID0gcGFzdGUodGVybV9uYW1lLCBmb3JtYXRDKHBfdmFsdWUsIGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMikpKSAlPiUKICBzZXBhcmF0ZV9yb3dzKGludGVyc2VjdGlvbikgJT4lCiAgbGVmdF9qb2luKC4sIHByb3Rfcm5hX2dlbmVfY29yX2RmLCBieSA9IGMoImludGVyc2VjdGlvbiIgPSAibWdpX3N5bWJvbCIpKSAlPiUKICBncm91cF9ieSh0ZXJtX25hbWUsIGdyb3VwLCBwX3ZhbHVlKSAlPiUKICBkcGx5cjo6c3VtbWFyaXplKG1lZF9jb3IgPSBtZWRpYW4oY29yLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBtdXRhdGUoeV9jb2wgPSBpZmVsc2UoZ3JvdXAgPT0gIk5lZ2F0aXZlIGNvcnJlbGF0aW9uIiwgeV9jb2xvcnNbMl0seV9jb2xvcnNbNF0pLAogICAgICAgICB5X2NvbCA9IGlmZWxzZShncm91cCA9PSAiTm8gY29ycmVsYXRpb24iLCB5X2NvbG9yc1szXSwgeV9jb2wpLAogICAgICAgICB5X2NvbCA9IGlmZWxzZShncm91cCA9PSAiUG9zaXRpdmUgY29ycmVsYXRpb24iLCB5X2NvbG9yc1sxXSwgeV9jb2wpKSAlPiUKICBhcnJhbmdlKGdyb3VwLCBwX3ZhbHVlKSAKCgpgYGAKCgpgYGB7ciBGaWd1cmUzQywgZmlnLmNhcCA9ICJGaWd1cmUgM0M6IEdlbmVzIHNob3cgdmFyaWFibGUgYWdyZWVtZW50IGJldHdlZW4gdHJhbnNjcmlwdCBhbmQgcHJvdGVpbiBhYnVuZGFuY2UgaW4gRE8gbUVTQ3MuIEhpc3RvZ3JhbSBkZXBpY3RpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwYWlyd2lzZSBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyBiZXR3ZWVuIHRyYW5zY3JpcHQgYW5kIHByb3RlaW4gYWJ1bmRhbmNlIG9mIGdlbmVzIHdpdGggY2hhcmFjdGVyaXN0aWMgR08gdGVybXMgb3ZlcnJlcHJlc2VudGVkIGluIGVhY2ggY2F0ZWdvcnkgYW5ub3RhdGVkIHVuZGVybmVhdGggaW4gbWF0Y2hpbmcgY29sb3JzIChncmVlbjogc2lnbmlmaWNhbnRseSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQsIG9yYW5nZTogc2lnbmlmaWNhbnRseSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQsIHB1cnBsZTogZ2VuZXMgd2l0aCBsaXR0bGUgb3Igbm8gY29ycmVsYXRpb24pLiIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQoKCgojIHBsb3QgcmVzdWx0cwp5X2NvbG9ycyA8LSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwobiA9IDQsIG5hbWUgPSAiRGFyazIiKQoKRmlndXJlM0NfZGF0YV9wYXJ0MSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gQ29ycmVsYXRpb24pICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoZmlsbCA9IEdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGLCBiaW53aWR0aCA9IDAuMDEsIGFscGhhID0gMC43KSArCiAgeGxhYigiR2VuZSBjb3JyZWxhdGlvbiIpICsKICB5bGFiKCIiKSsKICBzY2FsZV9maWxsX21hbnVhbChsaW1pdHMgPSBjKCAiTG93IixOQSwgIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIiksIHZhbHVlcyA9IGMoeV9jb2xvcnNbM10sImdyYXkiLHlfY29sb3JzWzJdLHlfY29sb3JzWzFdKSApICsKICB0aGVtZV9wdWJjbGVhbihiYXNlX3NpemUgPSAxOCwgYmFzZV9mYW1pbHkgPSAiUG9wcGlucyIpKwogIGdlb21fdmxpbmUoIGFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuKENvcnJlbGF0aW9uKSksIGxpbmV0eXBlID0gMiwgY29sID0gImJsYWNrIiwgc2l6ZSA9IDEpICsKICBhbm5vdGF0ZSgidGV4dCIsCiAgICB4ID0gbWVkaWFuKEZpZ3VyZTNDX2RhdGFfcGFydDEkQ29ycmVsYXRpb24sIG5hLnJtID0gVCkgLTAuMjUsIHkgPSAxMzUsCiAgICBsYWJlbCA9IHBhc3RlMCgiTWVkaWFuID0gXG4iLCBmb3JtYXRDKG1lZGlhbihGaWd1cmUzQ19kYXRhX3BhcnQxJENvcnJlbGF0aW9uLCBuYS5ybSA9IFQpLCBkaWdpdHMgPSAxLCBmb3JtYXQgPSJmIikpLAogICAgc2l6ZSA9IDYsCiAgICBmYW1pbHkgPSAiUG9wcGlucyIKICApKwogIHhsaW0oLTAuNSwgMSkrCiAgeWxpbSgwLDE1MCktPiBwMQoKCkZpZ3VyZTNDX2RhdGFfcGFydDIgJT4lIAogIGFycmFuZ2UoY29yKSAlPiUgCiAgbXV0YXRlKGxhYmVsMiA9IGZhY3RvcihwYXN0ZSh0ZXJtX25hbWUsIGZvcm1hdEMocF92YWx1ZSwgZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAyKSksCiAgICBsZXZlbHMgPSBGaWd1cmUzQ19kYXRhX3BhcnQzJHRlcm1fbmFtZQogICkpICU+JQogIG11dGF0ZShsYWJlbCA9IGZhY3RvcihpbnRlcnNlY3Rpb24sIGxldmVscyA9IHVuaXF1ZShpbnRlcnNlY3Rpb24pKSkgJT4lCiAgZ2dwbG90KCkgKwogIGFlcyh5ID0gbGFiZWwyLCB4ID0gY29yLCBjb2wgPSBncm91cDIsIGdyb3VwID0gdGVybV9uYW1lKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaGFwZSA9IDE1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKGxpbWl0cyA9IGMoImxvdyIsICJub25lIiwgIm5lZ2F0aXZlIiwgInBvc2l0aXZlIiksIHZhbHVlcyA9IGMoeV9jb2xvcnNbM10sImdyYXkiLHlfY29sb3JzWzJdLHlfY29sb3JzWzFdKSApICsKICB4bGFiKCJHZW5lIGNvcnJlbGF0aW9uIikgKwogIHlsYWIoIiIpICsKICB0aGVtZV9wdWJjbGVhbihiYXNlX3NpemUgPSAyMCwgYmFzZV9mYW1pbHkgPSAiUG9wcGlucyIpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBjb2xvciA9IChGaWd1cmUzQ19kYXRhX3BhcnQzJHlfY29sKSkKICApICsKICBzY2FsZV95X2Rpc2NyZXRlKHBvc2l0aW9uID0gInJpZ2h0IikgKwogIHhsaW0oLTAuNSwgMSktPiBwMgoKdG9wX3JvdyA8LSBwbG90X2dyaWQocDEsIE5VTEwsIHJlbF93aWR0aHMgPSBjKDEsIDAuNykpCmJvdHRvbV9yb3cgPC0gcGxvdF9ncmlkKE5VTEwsIHAyLCByZWxfd2lkdGhzID0gYygwLjA3LCAxKSkKb3JhX2Nvcl9wbG90PC0gcGxvdF9ncmlkKHRvcF9yb3csIGJvdHRvbV9yb3csIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMSwgMSkpIAoKb3JhX2Nvcl9wbG90CgpgYGAKCjxicj4KCmBgYHtyIEZpZ3VyZTNDX2RhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5jYXAgPSJDb3JyZWxhdGlvbiB2YWx1ZXMgdXNlZCBpbiBwbG90dGluZyBGaWd1cmUgM0MgdG9wIHBhbmVsIHdpdGggZ3JvdXBzIGNvbG9yZWQuIn0KCkZpZ3VyZTNDX2RhdGFfcGFydDEgJT4lCiAgbXV0YXRlX2lmKCBpcy5udW1lcmljLCByb3VuZCwgMikgJT4lIAogIGNyZWF0ZV9kdCgpCiAgCgpgYGAKCjxicj4KCmBgYHtyIE9SQV9yZXN1bHRzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuY2FwPSJMaXN0IG9mIG92ZXItcmVwcmVzZW50ZWQgYmlvbG9naWNhbCBwcm9jZXNzZXMgYW5kIHBhdGh3YXlzIGluIGdlbmVzIHdpdGggcG9zaXRpdmUsIG5lZ2F0aXZlIGFuZCBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRyYW5zY3JpcHQgYW5kIHByb3RlaW4gYWJ1bmRhbmNlLiJ9CgoKb3JhX2FsbF9jb3JyICU+JQogc2VsZWN0KAogICBgR3JvdXBgPWdyb3VwLCAKICAgYERhdGEgc291cmNlYCA9IHNvdXJjZSwKICAgIGBUZXJtIElEYCA9IHRlcm1faWQsCiAgICBgVGVybSBOYW1lYCA9IHRlcm1fbmFtZSwgCiAgICBgVGVybSBzaXplYCA9IHRlcm1fc2l6ZSwgCiAgICBgIyBvZiBpbnRlcnNlY3RpbmcgcHJvdGVpbnNgID0gaW50ZXJzZWN0aW9uX3NpemUsCiAgICAgRkRSID0gcF92YWx1ZQogICAgKSAlPiUgCiAgbXV0YXRlX2lmKCBpcy5udW1lcmljLCBmb3JtYXRDLCBkaWdpdHMgPTIpICU+JSAKICBjcmVhdGVfZHQoKQoKYGBgCgoKPGJyPgoKIyMjIyBGaWd1cmUgUzNFIAoKYGBge3IgRmlndXJlUzNFLCBmaWcuY2FwID0gIkZpZ3VyZSBTM0U6IEdlbmVzIHRoYXQgZG8gbm90IGZvcm0gY29tcGxleGVzIHNob3cgc2lnbmlmaWNhbnRseSBoaWdoZXIgY29ycmVsYXRpb24gYmV0d2VlbiB0cmFuc2NyaXB0IGFuZCBwcm90ZWluIGFidW5kYW5jZS4gQm94cGxvdCBjb21wYXJpbmcgdGhlIHBhaXJ3aXNlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGJldHdlZW4gdHJhbnNjcmlwdCBhbmQgcHJvdGVpbiBhYnVuZGFuY2UgZm9yIGdlbmVzIHRoYXQgYXJlIHBhcnQgb2YgcHJvdGVpbiBjb21wbGV4ZXMgKFRSVUUpIGFuZCB0aGF0IGRvIG5vdCBmb3JtIGNvbXBsZXhlcyAoRkFMU0UpLiIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTR9Cgpwcm90X3JuYV9nZW5lX2Nvcl9kZiAlPiUKICBtdXRhdGUoIHR5cGUgPSBpZmVsc2UoIGVuc2VtYmxfZ2VuZV9pZCAlaW4lIGNvbXBsZXguZ2VuZS5saXN0JGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICBGQUxTRSkKICAgICAgICAgICkgJT4lCiAgZ2dwbG90KCkgKwogIGFlcyh5ID0gY29yLCB4ID0gdHlwZSkgKwogIGdlb21fYm94cGxvdCggd2lkdGggPSAwLjI1LCBhZXMoIGNvbCA9IHR5cGUpLCBzaG93LmxlZ2VuZCA9IEYpKwogICNnZW9tX2RlbnNpdHkoYWVzKGNvbCA9IHR5cGUsIGZpbGwgPSB0eXBlKSwgc2hvdy5sZWdlbmQgPSBULCBiaW5zID0gNDAwLCBhbHBoYSA9IDAuNikgKwogIHlsYWIoIkNvcmVsYXRpb24iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyYXkiLCJyZWQiKSkgKwogICNnZ3RpdGxlKCJUcmFuc2NyaXB0IHZzIFByb3RlaW4gYWJ1bmRhbmNlIGZvciBnZW5lcyIpICsKICB0aGVtZV9wdWJjbGVhbihiYXNlX3NpemUgPSAxOCkrCiAgeGxhYigiQ29tcGxleCBmb3JtaW5nIikrCiAgc3RhdF9jb21wYXJlX21lYW5zKCAgbGFiZWwueCA9IDEuMiwgbGFiZWwueSA9IDEuMSkrCiAgeWxpbSggLS41LCAxLjIpIC0+IGZpZ3VyZV9zM2UKCgpnZ2FycmFuZ2UoZmlndXJlX3MzZSwgICAgICAgICAgCiAgICAgICAgICBsYWJlbHMgPSAiRSIsCiAgICAgICAgICBmb250LmxhYmVsID0gbGlzdCggc2l6ZSA9IDIwKQogICAgICAgICAgICAgICAgICAgICAgKQoKYGBgCgoKCgoKCg==

A work by Selcan Aydin

selcan.aydin@jax.org